C++ Modules规范阅读笔记。
10.3 Import declaration
模块导入声明的结构如下:
module-import-declaration:
import-keyword module-name attribute-specifier-seqopt ;
import-keyword module-partition attribute-specifier-seqopt ;
import-keyword header-name attribute-specifier-seqopt ;
导入声明只能出现在全局命名空间。在一个模块单元内,所有导入声明,以及带有导入声明的导出声明,必须在其他声明之前。
导入声明导入一个翻译单元的合集。
使用导入声明导入一个模块M,那么M所有的接口单元都被导入。
对于目标是模块片区的导入声明,只能出现在模块定义之后,而且只能作为该模块定义的片区。
如果导入声明的目标是一个合适的头文件单元(synthesized header unit),也就是经历了翻译阶段1到7的翻译单元,并且此头文件单元中不带模块声明。在此头文件单元中,所有的符号都被导出,并且添加到全局空间中。
如果有两个目标是importable header的导入声明:
- 如果头文件名字不同,那么这两个声明导入的是不同的头文件单元
- 否则,如果它们出现在同一个翻译单一,那么它们导入同一个头文件单元
- 否则,属于未定义行为
导入声明中出现的头文件名字,在预处理的时候也会被预处理器识别。
即便是在所有声明被导出的情况下,头文件单元中是具有内部链接性质的名字在允许的。头文件单元不能包含那么具有外部链接性质的非inline的函数或者变量。
当导入声明导入了一个翻译但与T,它也同时导入了所有T导入后导出的翻译单元。
模块实现单元不能被导出。
下面是例子。
翻译单元#1:
module M:Part;
翻译单元#2:
export module M;
export import :Part; // error: exported partition :Part is an implementation unit
某个模块的的实现单元不能导入模块自身:
module M;
import M; // error: cannot import M in its own unit
要避免循环引用
M1的接口单元:
export module M1;
import M2;
M2的接口单元:
export module M2;
import M3;
M3的接口单元:
export module M3;
import M1; // error: cyclic interface dependency M3→M1→M2→M3
10.4 Global module fragment
全局模块片段结构定义如下:
global-module-fragment:
module-keyword ; declaration-seqopt
一个模块单元可以有一部分片段属于全局模块。此分段内的声明属于全部模块。
然后文中列举了一大堆规则,说明什么是decl-reachable。也说明了什么是未定义行为。
在全局模块分段中的声明必须是对于翻译单元内部的任何声明都是decl-reachable的。否则就会被丢弃。丢弃的声明不会出现在模块单元之外的名字查找中,也不会出现在模块之外的模板实例化中。
例子1:
const int size = 2;
int ary1[size]; // unspecified whether size is decl-reachable from ary1
constexpr int identity(int x) { return x; }
int ary2[identity(2)]; // unspecified whether identity is decl-reachable from ary2
template<typename> struct S;
template<typename, int> struct S2;
constexpr int g(int);
template<typename T, int N>
S<S2<T, g(N)>> f(); // S, S2, g, and :: are decl-reachable from f
template<int N>
void h() noexcept(g(N) == N); // g and :: are decl-reachable from h
例子2:
foo.h:
namespace N {
struct X {};
int d();
int e();
inline int f(X, int = d()) { return e(); }
int g(X);
int h(X);
}
模块M的接口:
module;
#include "foo.h"
export module M;
template<typename T> int use_f() {
N::X x; // N::X, N, and :: are decl-reachable from use_f
return f(x, 123); // N::f is decl-reachable from use_f,
// N::e is indirectly decl-reachable from use_f
// because it is decl-reachable from N::f, and
// N::d is decl-reachable from use_f
// because it is decl-reachable from N::f
// even though it is not used in this call
}
template<typename T> int use_g() {
N::X x; // N::X, N, and :: are decl-reachable from use_g
return g((T(), x)); // N::g is not decl-reachable from use_g
}
template<typename T> int use_h() {
N::X x; // N::X, N, and :: are decl-reachable from use_h
return h((T(), x)); // N::h is not decl-reachable from use_h, but
// N::h is decl-reachable from use_h<int>
}
int k = use_h<int>();
// use_h<int> is decl-reachable from k, so
// N::h is decl-reachable from k
模块M的实现:
module M;
int a = use_f<int>(); // OK
int b = use_g<int>(); // error: no viable function for call to g;
// g is not decl-reachable from purview of
// module M's interface, so is discarded
int c = use_h<int>(); // OK
(本篇完)