模块分区实现单元可脱离接口单元吗?MSVC编译报错求助
问题回顾
cppreference给出过无需对应接口单元即可使用模块分区实现单元的示例:
/////// A-B.cpp export module A:B; ... /////// A-C.cpp module A:C; ... /////// A.cpp export module A; import :C; export import :B; ...
但在MSVC中,将分区改为实现单元(去掉export、改用.cpp扩展名)时会报错:module partition 'rendering' for module unit 'game' was not found,同时对主模块未export import分区却不报错存在疑问。
一、实现单元分区编译错误的原因及解决办法
MSVC处理C++模块时,对实现单元分区有个关键约束:实现单元分区必须和主模块接口单元处于同一编译上下文,因为不带export的实现单元分区不会被编译器当作模块接口的一部分自动扫描关联。
你遇到的错误就是因为编译器没把rendering.cpp(实现单元分区)和game.ixx(主模块接口单元)关联起来。解决方式很直接:
- 命令行编译:把两个文件放在同一编译命令里,比如:
cl /std:c++20 game.ixx rendering.cpp - Visual Studio项目:确保
rendering.cpp被添加到项目中,且项类型设为C/C++ 编译器(默认就是,若之前被排除过需检查)。
另外注意:.ixx是MSVC默认识别的模块接口单元扩展名,.cpp则需要编译器通过代码里的module声明判断,但实现单元分区必须和主模块明确绑定,所以必须保证两者一起编译。
二、主模块未export import分区却不报错的原因
先把你引用的cppreference内容翻译为中文:
模块分区可以是模块接口单元(当模块声明带
export时)。这类分区必须被主模块接口单元导出导入(export-import),且当外部导入该模块时,其导出内容会对外可见。
这里的规则只针对带export的接口单元分区——也就是你第一种写法里的rendering.ixx。如果你的需求是让该分区的内容仅在模块内部使用,那么主模块只需要import :rendering而不需要export import,这完全符合标准:
- 对于实现单元分区(第二种写法):
import :rendering只是让主模块能调用该分区的内部函数,本来就不需要对外暴露,自然不用export。 - 对于接口单元分区:如果只是模块内部使用,不对外暴露,也可以只
import而不export import,此时外部导入game模块看不到rendering的导出内容,这是合法的。cppreference的描述是强制要求当你需要让外部看到接口分区的导出内容时才必须用export import,而非所有接口分区都要这么做。
内容的提问来源于stack exchange,提问作者user25749542

