非导出声明和私有模块片段中的声明有什么区别?

What is the difference between non-export declarations and declarations in private module fragment?

cppreference.com about modules 上说 export:

Module interface units can export declarations and definitions, which can be imported by other translation units. [ … ]
All declarations and definitions exported in the module interface units of the given named module will be available in the translation unit using the import declaration.

据此猜测,我会 export 模块用户想要或需要使用它的所有内容。未 export 的所有内容都是模块的实现细节和 import 用户关注的 none。

它还告诉我

a private module fragment [ … ] allows a module to be represented as a single translation unit without making all of the contents of the module reachable to importers.

将某些东西放入私有模块片段与不 export 有什么区别? 我想“使用进口声明在翻译单元中可用”和“进口商可获得”之间是有区别的。但从实际的角度来看,这有什么区别呢?作为指导,我什么时候将某些东西放入私有模块片段中,什么时候不导出它?

(我在引号内突出显示。)

答案在cppreference

上有更详细的解释

在这里引用它是为了回答的完整性。

Private module fragment

Primary module interface unit can be suffixed by a private module fragment, which allows a module to be represented as a single translation unit without making all of the contents of the module reachable to importers.


module : private ;

declaration-seq(optional)

Private module fragment ends the portion of the module interface unit that can affect the behavior of other translation units. If a module unit contains a private module fragment, it will be the only module unit of its module.

export module foo;
export int f();
 
module :private; // ends the portion of the module interface unit that
                 // can affect the behavior of other translation units
                 // starts a private module fragment
 
int f() {        // definition not reachable from importers of foo
    return 42;
}

即因此,您可以同时 导出声明并隐藏 定义。

用例说明here

Thanks to a private module fragment, you can implement a module in one file and declare its last part as its implementation using module :private;. Consequently, a modification of the private module fragment does not cause recompilation.

What is the difference between putting something in the private module fragment than to just not exporting it

在实现方面的原则区别是 non-exported 模块接口中的定义可以被属于同一模块的其他代码段(实现单元和其他接口单元)导入模块)。即使您不导出它们,他们也可以访问这些声明。因此,这些声明必须(在某种程度上)存在于编译器用于该模块的任何文件中。

相比之下,私有模块片段代码对模块的任何可访问接口没有贡献。它就像一个模块实现单元。

但问题是:您无法区分。为什么?如果主模块接口有私有模块片段,则 不能 属于同一模块的任何其他文件。这是明确禁止的。私有模块片段作为一种工具存在,以支持您希望将完整模块作为单个文件发布的情况。没有什么是私有模块片段可以做的,而模块实现单元做不到的。

因此,如果可能存在私有模块片段(即:它是一个 single-file 模块),则导入该模块的代码将看不到未导出的声明。

私有模块片段背后的主要目的是无法从其中导出内容。这可以防止您在 single-file 实施中不小心这样做。

实际的答案是使 类 在客户中 不完整

export module A;
struct X;
export X* make();

module :private;
struct X {};
X* make() {return new X;}

省略 module :private; 行会使 X 在导入器中完成,因为 export 会影响 名称查找 ,而不是声明可达性。