c++20模块需严格区分接口单元(export module name;)和实现单元(module name;),import仅可见export内容,构建须适配编译器参数与cmake模块属性,否则退化为头文件模式。

模块声明和定义怎么写才不被编译器报错
模块不是把 #include 换成 import 就完事。C++20 要求模块接口单元(interface unit)必须以 module 关键字开头,且只能有一个模块声明;实现单元(implementation unit)用 module module_name; 声明归属,不能用 export module。
- 接口文件(如
math.mpp)必须写:export module math;,后面跟export的函数或类声明 - 实现文件(如
math.cpp)写:module math;,不加export,只提供定义 - 不能在头文件里混用
export module和#include—— 编译器会直接拒绝,报错类似error: module declaration must be the first non-comment, non-whitespace token - MSVC 要求模块文件后缀为
.ixx或显式用/experimental:module /module:interface控制;Clang 和 GCC 则更倾向.mpp+-x c++-system-header类参数,不统一
import 之后为什么还是找不到符号
导入模块 ≠ 自动可见所有内容。import 只让 export 过的声明进入当前作用域,没 export 的函数、类型、宏、静态变量全都不见。
- 如果
math.mpp里写了int helper();但没加export,哪怕它在export module math;下面,import math;后也调不到helper() -
export不能修饰局部变量或函数内定义的类型;也不能修饰using指令(如using namespace std;),但可以修饰using声明(如export using std::vector;) - 模块内
#include <vector></vector>是允许的,但不会自动导出std::vector—— 必须显式export using std::vector;或export template class std::vector<int>;</int>
混合使用 #include 和 import 时链接失败或 ODR 违反
头文件和模块共存是过渡期常态,但危险点在于:同一个实体(比如 class Widget)若既从传统头文件中 #include 进来,又被某个模块 export 过,就可能触发 ODR(One Definition Rule)违规 —— 编译器未必立刻报错,但链接阶段可能符号重复,或运行时行为异常。
- 避免对同一库做双路径暴露:比如一边用
#include <fmt></fmt>,一边又自己封装了export module fmt_wrapper;并export import <fmt></fmt>(GCC/Clang 目前不支持直接 import 标准头,MSVC 有实验性import std;,但不可移植) - 第三方库未提供模块接口时,老实用
#include;想封装,就用模块“桥接”,但桥接模块里不要export头文件里的定义,只export你自己的薄包装层(例如export inline std::string to_string_v2(int x) { return fmt::to_string(x); }) - 模块编译产物(如
.pcm或.ifc)和目标平台强绑定:MSVC 的.ifc不能给 Clang 用,GCC 的.gcm也不兼容 —— 混合构建系统(如 CMake + 多编译器)下,模块缓存要按 compiler-id 分开管理,否则静默失效
构建系统怎么实际跑起来(以 CMake 3.27+ 为例)
CMake 对模块的支持仍偏底层,没到“开箱即用”程度。关键不是写对语法,而是让生成的构建规则正确传递模块依赖与接口路径。
立即学习“C++免费学习笔记(深入)”;
- 模块接口文件需用
set_property(SOURCE math.mpp PROPERTY CXX_MODULE_INTERFACE TRUE)显式标记,否则 CMake 当普通源文件处理 - 必须手动指定模块映射路径:
target_compile_options(mylib PRIVATE $<join:>,=></join:>),不然import找不到模块名对应物理文件 - 模块间依赖要用
target_link_libraries(other_module INTERFACE mylib),而不是target_include_directories—— 后者对模块无效 - 调试时发现模块没生效?检查
compile_commands.json里是否出现了-fmodules-ts(Clang)、/experimental:module(MSVC)或-fmodules(GCC),缺一个就退回头文件模式










