翻訳単位ローカルエンティティ (C++20以降)
From cppreference.com
翻訳単位ローカル (TU-local) エンティティは、ローカルであるべきエンティティ (他の翻訳単位では使用されないもの) が、他の翻訳単位で公開され、使用されることを防ぐために導入されます。
Understanding C++ Modules: Part 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-local エンティティ
エンティティがTU-localであるのは、以下のいずれかの場合です。
- 以下のいずれかの型、関数、変数、またはテンプレートである場合。
- クラス指定子、関数本体、または初期化子の外で定義されている名前のない型、またはTU-local エンティティのみを宣言するために使用される定義型指定子 (型指定子、クラス指定子、または列挙指定子) によって導入された型である場合。
- TU-local テンプレートの特殊化である場合。
- いずれかの TU-local テンプレート引数を持つテンプレートの特殊化である場合、または
- その (おそらくインスタンス化された) 宣言が露出 (後述) であるテンプレートの特殊化である場合。
// 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-localであるのは、以下のいずれかの場合です。
- それが TU-local 関数であるか、TU-local 関数へのポインタであるか、または TU-local 変数に関連付けられたオブジェクトである場合、または
- それがクラスまたは配列型のオブジェクトであり、そのサブオブジェクトのいずれか、またはその参照型の非静的データメンバーが参照するオブジェクトや関数のいずれかが TU-local であり、かつ定数式で使用可能である場合。
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
[編集] 露出 (Exposures)
宣言 D がエンティティ E を名前解決するのは、以下のいずれかの場合です。
- D がそのクロージャ型が E であるラムダ式を含む場合。
- E が関数または関数テンプレートではなく、D が E を示す id-式、型指定子、ネストされた名前指定子、テンプレート名、またはコンセプト名を含む場合、または
- E が関数または関数テンプレートであり、D が E を名前解決する式、または E を含むオーバーロードのセットを参照する id-式を含む場合。
// 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-local エンティティを名前解決する場合であり、ただし以下のものを除く場合です。
- 非インライン関数または関数テンプレートの関数本体 (ただし、プレースホルダー型を使用する宣言された戻り型を持つ関数の (おそらくインスタンス化された) 定義の推論された戻り型は除く)。
- 変数または変数テンプレートの初期化子 (ただし、変数の型は除く)。
- クラス定義内のフレンド宣言、および
- odr-useではない定数式で初期化された、内部リンケージまたはリンケージのない非揮発性 const オブジェクトまたは参照へのすべての参照。
または、TU-local 値で初期化された constexpr 変数を定義する場合。
| このセクションは未完成です 理由: 露出の例が不足しています。 |
[編集] TU-local 制約
モジュールインターフェース単位 (プライベートモジュールフラグメント (もしあれば) の外) またはモジュールパーティション内の非 TU-local エンティティの (おそらくインスタンス化された)宣言、またはその推論ガイドが露出である場合、プログラムは不適格です。他のコンテキストでのそのような宣言は非推奨です。
ある翻訳単位に現れる宣言が、ヘッダー単位ではない別の翻訳単位で宣言された TU-local エンティティを名前解決する場合、プログラムは不適格です。テンプレート特殊化のためにインスタンス化された宣言は、特殊化のインスタンス化の点に現れます。
| このセクションは未完成です 理由: 制約の例が不足しています。 |
[編集] 例
翻訳単位 #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 }
| このセクションは未完成です 理由: 例が複雑すぎるため、より良い配置が必要です。 |