翻译单元本地实体 (自 C++20 起)
来自 cppreference.com
翻译单元本地 (TU-本地) 实体的引入是为了防止本来应该在本地(不在任何其他翻译单元中使用)的实体被公开并在其他翻译单元中使用。
来自 理解 C++ 模块:第 2 部分 的一个示例说明了没有约束公开带来的问题。
// Module unit without TU-local constraints export module Foo; import <iostream>; namespace { class LolWatchThis { // internal linkage, cannot be exported static void say_hello() { std::cout << "Hello, everyone!\n"; } }; } export LolWatchThis lolwut() { // LolWatchThis is exposed as return type return LolWatchThis(); }
// main.cpp import Foo; int main() { auto evil = lolwut(); // 'evil' has type of 'LolWatchThis' decltype(evil)::say_hello(); // definition of 'LolWatchThis' is not internal anymore }
内容 |
[编辑] TU-本地实体
如果一个实体是:
- 类型、函数、变量或模板,并且:
- 具有 内部链接 的名称,或者
- 没有链接的名称,并且是在 TU-本地实体的定义内声明的,或者是由 lambda 表达式 引入的,
- 在 类说明符、函数体或初始化器之外定义的无名类型,或者是由用于声明仅 TU-本地实体的定义类型说明符(类型说明符、类说明符或枚举说明符)引入的,
- TU-本地模板的特化,
- 具有任何 TU-本地模板参数的模板的特化,或者
- 其(可能实例化的)声明是公开(在下面定义)的模板的特化。
// TU-local entities with internal linkage namespace { // all names declared in unnamed namespace have internal linkage int tul_var = 1; // TU-local variable int tul_func() { return 1; } // TU-local function struct tul_type { int mem; }; // TU-local (class) type } template<typename T> static int tul_func_temp() { return 1; } // TU-local template // TU-local template specialization template<> static int tul_func_temp<int>() { return 3; } // TU-local specialization // template specialization with TU-local template argument template <> struct std::hash<tul_type> { // TU-local specialization std::size_t operator()(const tul_type& t) const { return 4u; } };
本节不完整 原因:缺少规则 #1.2、#2 和 #5 的示例 |
如果一个值或对象是:
- 它是,或者是指向 TU-本地函数的指针,或者是指向与 TU-本地变量关联的对象的指针,或者
- 它是类或数组类型的对象,并且它的任何 子对象 或任何其非静态数据成员(引用类型)所引用的对象或函数是 TU-本地的,并且在 常量表达式中可用。
static int tul_var = 1; // TU-local variable static int tul_func() { return 1; } // TU-local function int* tul_var_ptr = &tul_var; // TU-local: pointer to TU-local variable int (* tul_func_ptr)() = &tul_func; // TU-local: pointer to TU-local function constexpr static int tul_const = 1; // TU-local variable usable in constant expressions int tul_arr[] = { tul_const }; // TU-local: array of constexpr TU-local object struct tul_class { int mem; }; tul_class tul_obj{tul_const}; // TU-local: has member constexpr TU-local object
[编辑] 公开
如果一个声明 D 命名 一个实体 E,则:
- D 包含一个 lambda 表达式,其闭包类型是 E,
- 如果 E 不是函数或函数模板,而 D 包含表示 E 的标识符表达式、类型说明符、嵌套名称说明符、模板名称或概念名称,或者
- 如果 E 是函数或函数模板,而 D 包含命名 E 的表达式或引用包含 E 的重载集的标识符表达式。
// lambda naming auto x = [] {}; // names decltype(x) // non-function (template) naming int y1 = 1; // names y1 (id-expression) struct y2 { int mem; }; y2 y2_obj{1}; // names y2 (type-specifier) struct y3 { int mem_func(); }; int y3::mem_func() { return 0; } // names y3 (nested-name-specifier) template<typename T> int y4 = 1; int var = y4<y2>; // names y4 (template-name) template<typename T> concept y5 = true; template<typename T> void func(T&&) requires y5<T>; // names y5 (concept-name) // function (template) naming int z1(int arg) { std::cout << "no overload"; return 0; } int z2(int arg) { std::cout << "overload 1"; return 1; } int z2(double arg) { std::cout << "overload 2"; return 2; } int val1 = z1(0); // names z1 int val2 = z2(0); // names z2 ( int z2(int) )
如果声明命名了 TU 本地实体,则它是一个 *公开*,忽略以下内容:
- 非内联函数或函数模板的函数体(但不包括具有声明的返回类型且使用 占位符类型 的(可能实例化的)定义的函数的推断返回类型),
- 变量或变量模板的初始化程序(但不包括变量的类型),
- 类定义中的友元声明,以及
- 对非易失性 const 对象或具有内部或无链接的引用,该引用使用非 odr-use 的常量表达式初始化,
或定义初始化为 TU 本地值的 constexpr 变量。
本节不完整 原因:缺少公开的示例 |
[edit] TU 本地约束
如果(可能实例化的)声明 或 推断指南 在 模块接口单元(在私有模块片段中,如果有的话)或模块分区中对非 TU 本地实体进行公开,则程序格式错误。在任何其他上下文中进行这样的声明都是不推荐的。
如果一个翻译单元中的声明命名了另一个翻译单元中声明的 TU 本地实体,而该实体不是头文件单元,则程序格式错误。为模板特化实例化的声明出现在特化的实例化点。
本节不完整 原因:缺少约束的示例 |
[edit] 示例
翻译单元 #1
export module A; static void f() {} inline void it() { f(); } // error: is an exposure of f static inline void its() { f(); } // OK template<int> void g() { its(); } // OK template void g<0>(); decltype(f) *fp; // error: f (though not its type) is TU-local auto &fr = f; // OK constexpr auto &fr2 = fr; // error: is an exposure of f constexpr static auto fp2 = fr; // OK struct S { void (&ref)(); } s{f}; // OK: value is TU-local constexpr extern struct W { S &s; } wrap{s}; // OK: value is not TU-local static auto x = []{ f(); }; // OK auto x2 = x; // error: the closure type is TU-local int y = ([]{ f(); }(), 0); // error: the closure type is not TU-local int y2 = (x, 0); // OK namespace N { struct A {}; void adl(A); static void adl(int); } void adl(double); inline void h(auto x) { adl(x); } // OK, but a specialization might be an exposure
翻译单元 #2
module A; void other() { g<0>(); // OK: specialization is explicitly instantiated g<1>(); // error: instantiation uses TU-local its h(N::A{}); // error: overload set contains TU-local N::adl(int) h(0); // OK: calls adl(double) adl(N::A{}); // OK; N::adl(int) not found, calls N::adl(N::A) fr(); // OK: calls f constexpr auto ptr = fr; // error: fr is not usable in constant expressions here }
本节不完整 原因:示例过于复杂,需要更好的安排 |