Nic*_*las 14 c++ c++20 c++-modules
C++20 标准似乎定义了模块单元的两类:接口/实现单元,以及模块单元是否是分区。这两个分类看起来是正交的:您可以拥有一个是分区的实现单元、一个不是分区的接口单元,等等。
分类的接口/实现轴似乎是关于你能做什么import和不能做什么。但如果这是真的,那么作为命名分区的实现单元有什么意义呢?难道你不能让这个实现单元不是一个分区吗?
这两个概念真的是正交的,还是有些相互依赖的?如果是后者,他们之间的依赖程度如何?
Nic*_*las 11
模块单元分类的这两个轴是正交的,从某种意义上说,模块可以独立地成为这些分类的任意组合的一部分。然而,该标准针对这 4 种分类中的每一种定义了许多专门规则,这使得每种分类的使用不仅仅是分类定义所指示的。
在我们查看这些组合之前,我们首先需要定义要分类的内容。
接口单元不是可以导入的东西。好吧,你可以,但这不是“接口单元”的定义。模块单元是模块的接口单元,因为它是模块接口M的组件。这意味着,如果有人导入该模块,构建系统将需要构建该模块的所有接口单元。在导入之前不需要构建模块的实现单元MMMMM。
这就是接口/实现分类的全部含义(虽然这不是它所做的全部,但我们会做到这一点)。实现单元在概念上是模块的一部分M,但它们不是模块接口的一部分。
重要的是要注意“模块的一部分”的含义M。如果一个实体是在 的权限范围内声明的M,那么它就是 的一部分M。因此,如果您想再次声明它(比方说,因为您正在定义它),则第二个声明也必须在M( [basic.link]/10 )的权限内。
这就是各种实现单元的要点:在M不对其接口做出贡献的情况下处于其权限范围内。
标准中没有关于不是分区的模块单元的术语,因此我将此类模块单元称为“纯”。
作为模块分区X的模块单元M可以通过分区导入语法导入:import :X。这只能由属于 的一部分的模块单元来完成M。纯模块单元不能以这种方式导入。
所以分区与纯分类是关于模块内的模块单元是否可以通过特殊语法导入同一模块内的某些模块单元。
同样重要的是要注意导入某些内容的含义。导入内容是在翻译单元的基础上完成的。导入非分区模块意味着导入该模块的所有接口模块单元TU。导入模块分区就是只导入该分区单元。
但是,仅对于由声明它们的模块外部的代码导入的声明export 才重要。因此,如果 的某个模块单元导入 的分区单元,它将看到该分区单元权限中的所有声明,无论它们是否是 ed ( [basic.scope.namespace]/2 ) 。MMexport
现在,让我们检查 C++ 为这四种组合中的每一种定义的所有特殊情况规则。至惠特:
这种组合附加了如此多的特殊规则,以至于标准给它起了一个名字:模块的主要接口单元M。
如果我们只看上面的规则, 的一个主要接口单元M是 的接口的一个组件M。M并且由于它是纯的,因此不能通过分区语法导入主接口单元。
但随后该标准在此基础上设置了更多规则:
对于任何模块M,都应该有且只有一个主接口单元M([module.unit]/2)。
的所有分区接口单元M 必须由( [module.unit]/3export import )的主接口单元编辑(直接或间接)。M
如果 没有其他实现或接口单元M,则该文件可能有一个私有模块片段,用于将非导出的内容放入M单个文件([module.private.frag])中。
简而言之:如果构建系统需要构建 module M,那么真正意味着它需要构建此文件(及其导入的任何内容)。该文件是定义将公开的内容的导入根import M;。
此类模块单元是模块接口的组成部分M,因此必须经过编译才能生成模块M。但这已得到处理,因为主要接口单元必须包括所有这些。它们也可以被包括......我们知道,因为主要接口单元必须包括它们。
因此,对于这一点没有任何其他地方未涵盖的特殊规则。
接口分割单元的意义只是将大模块接口分割成多个文件的工具。
作为实现单元,它们不参与模块的接口。并且作为纯模块单元,它们不能作为分区导入。这意味着其中发生的所有事情都保留在其中(就导入任何内容而言)。
但他们也有一些特殊规则:
M 隐式 的所有纯实现单元import M;([module.unit]/8)。
他们不能明确地 import M;([module.import]/9)。
如果实现单元的目的是能够定义模块的接口功能,那么这些规则就有意义。如前所述,只有 的模块单元M可以定义作为 的M接口一部分的声明。所以这些是大多数定义所在的文件。
M因此,为了方便起见,它们也可能隐式包含 的接口。
这是一个模块单元,不是其模块接口的一部分。但由于它是一个分区,因此可以被.NET的其他模块单元导入M。
这听起来很矛盾,直到你遇到这个特殊情况规则:
export import分区实现单元([module.import]/8)。因此,即使接口单元导入实现分区,它也无法导出该分区。实现单元也不能导出其中定义的任何内容(不允许您export稍后将未导出的内容重新声明为 ed)。
但请记住,这只export 适用于导入非分区(即:其他模块)。由于分区只能由其自己模块的成员导入,并且导入分区中的所有声明都可供导入代码使用,因此我们拥有的是包含模块实现私有声明的模块单元,但需要可供多个模块实现单元访问。
这一点尤其重要,因为模块名称是全局的,而分区名称是模块的本地名称。通过将内部共享代码放入实现分区中,您不会因为模块的实现细节而污染模块名称的全局空间。
| 归档时间: |
|
| 查看次数: |
747 次 |
| 最近记录: |