リフレクション演算子 (C++26 以上)
ja.cppreference.net より
単項 ^^ 演算子、リフレクション演算子と呼ばれ、指定された言語構成要素のリフレクションを生成します。その型は std::meta::info です。
構文
^^ ::
|
(1) | ||||||||
^^ リフレクション名
|
(2) | ||||||||
^^ 型識別子
|
(3) | ||||||||
^^ 識別子式
|
(4) | ||||||||
| リフレクション名 | - | 識別子(オプションで 修飾可能、オプションで template 曖昧解決子を使用)。この形式は 型識別子 および 識別子式 |
| よりも優先されます。型識別子 | - | 型識別子 |
| 識別子式 | - | 識別子式 |
構文上、^^ のオペランドを形成できる最も長いトークン列が解析されます。結果がテンプレートを表す場合、式の直後に < が続いてはなりません。
static_assert(std::meta::is_type(^^int())); // ^^int() represents the type int()
// not a function call to ^^int
template<bool> struct X {};
consteval bool operator<(std::meta::info, X<false>) { return false; }
consteval void g(std::meta::info r, X<false> xv) {
r == ^^int && true; // error: ^^ applies to the type-id int&&
r == ^^int & true; // error: ^^ applies to the type-id int&
r == (^^int) && true; // OK
r == ^^int &&&& true; // error: int &&&& is not a valid type-id
^^X < xv; // error: reflect-expression that represents a template is followed by <
(^^X) < xv; // OK
^^X<true> < xv; // OK
}
説明
1) 式
^^:: はグローバル名前空間を表します。2)
^^reflection-name では、リフレクション名 が 名前探索され、以下のように表現が決定されます:
- 名前探索が using 宣言子を置き換えた宣言を見つけた場合、式は無効です。using-declarator、
- それ以外の場合、名前探索が 名前空間エイリアス、名前空間、または コンセプト を見つけた場合、結果はそのエンティティを表します。
- それ以外の場合、名前探索が テンプレート を見つけた場合:
- 名前探索が 注入されたクラス名 を見つけた場合:
- template 曖昧解決子 が存在する場合、結果は注入されたクラス名によって指定されたクラステンプレートを表します。
- それ以外の場合、注入されたクラス名は型名として考慮されたときに曖昧であってはなりません(そうでなければ式は無効です)。結果はそのように指定された型を表します。
- それ以外の場合、名前探索がオーバーロード集合を見つけた場合、そのオーバーロード集合は一意の関数テンプレートの宣言のみを含んでいなければなりません。結果はその関数テンプレートを表します。
- それ以外の場合、名前探索が クラステンプレート、変数テンプレート、または エイリアステンプレート を見つけた場合、結果はそのテンプレートを表します。
- それ以外の場合、名前探索が型 テンプレートパラメータ を見つけた場合、結果は対応する引数の型を表します。
- それ以外の場合、名前探索が typedef 名 または 型エイリアス を見つけた場合、結果はその型エイリアスを表します。
template<typename T>
struct S {
static constexpr std::meta::info r = ^^T;
using type = T;
};
static_assert(S<int>::r == ^^int); // OK
static_assert(^^S<int>::type != ^^int); // OK
typedef struct X {} Y;
typedef struct Z {} Z;
constexpr std::meta::info e = ^^Y; // OK, represents the type alias Y
constexpr std::meta::info f = ^^Z; // OK, represents the type alias Z, not the type
3) 式
^^type-id は次のように決定されるエンティティを表します:
- 型識別子 が プレースホルダー型(例:
auto)を指定する場合、式は無効です。 - それ以外の場合、型識別子 がテンプレート引数リストを持つ エイリアステンプレート を指定する場合、結果はそのように指定された型エイリアスを表します。(その他の形式の型エイリアス名は リフレクション名 として扱われ、結果もその型エイリアスを表します。)
- それ以外の場合、結果は 型識別子 によって示される型を表します。
4) 式
^^id-expression は次のように決定されるエンティティを表します:
- 識別子式 が以下を表す場合:
- ラムダの init-capture によって宣言された変数、
- 関数ローカルの事前定義変数 (
__func__)、 - ローカルパラメータ(
requires式によって宣言されたもの)、または - ローカルエンティティであり、そのエンティティが導入された地点とリフレクト式の間にラムダスコープが介在するもの(エンティティがキャプチャされているかどうかに関わらず)、
- 式は無効です。
- それ以外の場合、識別子式 がオーバーロード集合を表す場合、オーバーロード解決 は一意の関数を選択しなければなりません。結果はその関数を表します。
template<typename T> void fn() requires (^^T != ^^int);
template<typename T> void fn() requires (^^T == ^^int);
template<typename T> void fn() requires (sizeof(T) == sizeof(int));
constexpr std::meta::info a = ^^fn<char>; // OK
constexpr std::meta::info b = ^^fn<int>; // error: ambiguous
- それ以外の場合、識別子式 が変数、構造化束縛、列挙子、または 非静的データメンバ を表す場合、結果はそのエンティティを表します。
- それ以外の場合(例: 識別子式 が非型 テンプレートパラメータ や パックインデックス 式を表す場合)、式は無効です。
オペランドは 未評価オペランド です。
注記
リフレクション値は、std::meta::reflect_constant、std::meta::reflect_object、std::meta::reflect_function、または デフォルト初期化 された std::meta::info によっても生成できます。さらに、既存の <std::meta::info> オブジェクトに対して meta 関数を呼び出すことによってリフレクション値を得ることもできます。
型エイリアスが 型識別子 の一部として現れる場合、リフレクション演算子はその型エイリアスを保持しません。
using T = int;
static_assert(^^T != ^^int);
static_assert(^^T& == ^^int&);
static_assert(^^T const == ^^const int);
例
このコードを実行する
int arr[] = {1, 2, 3};
auto [a1, a2, a3] = arr;
[[=1]] void fn(int n);
enum Enum { A };
using Alias = int;
struct S { int mem; };
template<auto> struct TCls {};
template<auto> void TFn();
template<auto> int TVar;
template<auto N> using TAlias = TCls<N>;
template<auto> concept Concept = true;
namespace NS {}
namespace NSAlias = NS;
constexpr auto r_arr = ^^arr; // represents a variable
constexpr auto r_sb = ^^a3; // represents a structured binding
constexpr auto r_fn = ^^fn; // represents a function
constexpr auto r_enum = ^^Enum::A; // represents an enumerator
constexpr auto r_alias = ^^Alias; // represents a type alias
constexpr auto r_type = ^^S; // represents a type
constexpr auto r_mem = ^^S::mem; // represents a class member
constexpr auto r_tcls = ^^TCls; // represents a class template
constexpr auto r_tfn = ^^TFn; // represents a function template
constexpr auto r_tvar = ^^TVar; // represents a variable template
constexpr auto r_ttype = ^^TAlias; // represents an alias template
constexpr auto r_cncpt = ^^Concept; // represents a concept
constexpr auto r_ns = ^^NS; // represents a namespace
constexpr auto r_ns2 = ^^NSAlias; // represents a namespace alias
int main() {}
関連項目
(C++26) |
値または テンプレートパラメータオブジェクト を表すリフレクションを返します。定数テンプレート引数として使用するのに適しています (関数テンプレート) |
(C++26) |
オブジェクトを表すリフレクションを返します。定数テンプレート引数として使用するのに適しています (関数テンプレート) |
(C++26) |
関数を表すリフレクションを返します。定数テンプレート引数として使用するのに適しています (関数テンプレート) |