反射的擴充功能
C++ 反射擴充功能,ISO/IEC TS 23619:2021,指定了對核心語言的修改,並定義了本頁列出的 C++ 標準函式庫新元件。
反射技術規範 (Reflection TS) 基於 C++20 標準(除了概念的定義是按照概念技術規範 (Concepts TS) 的風格指定)。
[編輯] 核心語言變更
[編輯] reflexpr 指定符
一個 reflexpr-指定符 的形式為 reflexpr ( reflexpr-運算元 ),並指定一個後設物件類型(見下文)。
reflexpr-運算元 可以是以下之一
::
|
(1) | ||||||||
| 類型識別碼 | (2) | ||||||||
| 巢狀名稱指定符(可選) 命名空間名稱 | (3) | ||||||||
| 識別碼表達式 | (4) | ||||||||
( 表達式 ) |
(5) | ||||||||
| 函式呼叫表達式 | (6) | ||||||||
| 函式樣式類型轉換表達式 | (7) | ||||||||
其中 函式呼叫表達式 為
後置表達式 ( 表達式清單(可選) ) |
|||||||||
且 函式樣式類型轉換表達式 是以下執行 顯式型別轉換 的表達式類型
簡單類型指定符 ( 表達式清單(可選) ) |
(1) | ||||||||
類型名稱指定符 ( 表達式清單(可選) ) |
(2) | ||||||||
| 簡單類型指定符 大括號初始器清單 | (3) | ||||||||
| 類型名稱指定符 大括號初始器清單 | (4) | ||||||||
reflexpr-指定符 的運算元應為 類型、命名空間、列舉器、變數、資料成員、函式參數、被捕捉的實體、函式呼叫表達式 或 函式樣式類型轉換表達式,以及括號表達式。reflexpr(::) 反射全域命名空間。
對於形式為 ( 表達式 ) 的 reflexpr-運算元,該 表達式 應為(可能有多層括號的)函式呼叫表達式 或 函式樣式類型轉換表達式。
如果未加括號的運算元可以被視為 類型識別碼 或 函式樣式類型轉換表達式,則它將被視為 類型識別碼。括號可用於區分函式樣式型別轉換和 類型識別碼。例如,給定一個帶有預設建構式的類別類型 X,reflexpr(X()) 反射函式類型 X(),而 reflexpr((X())) 反射表達式 X()。
如果運算元同時指定了別名和類別名稱,則由 reflexpr-指定符 表示的類型會反射該別名並滿足 reflect::Alias。
如果運算元指定了一個其宣告包含在區塊作用域中的名稱,且該具名實體既未被捕捉也不是函式參數,則程式碼格式不正確。
[編輯] 後設物件類型
一個 *後設物件類型* 是一個不具名、不完整、命名空間作用域的類別類型。一個類型當且僅當它是後設物件類型時,才滿足 reflect::Object 概念。後設物件類型可能會根據 reflexpr 的運算元滿足其他概念。
重複將 reflexpr 應用於相同的運算元是否會產生相同的類型或不同的類型是未指定的。如果後設物件類型反射一個不完整的類別類型,則某些類型轉換無法套用。
後設物件類型允許透過類型特性或類型轉換檢查 reflexpr 運算元的一些屬性。
[編輯] 多載解析
如果函式呼叫表達式中的 後置表達式 是類別類型,即 e 在函式呼叫表達式 e(args) 中是類別類型,則不應使用 後置表達式 (e) 類型的 使用者定義轉換函式。
如果 後置表達式 不是類別類型,它應命名一個函式,該函式是多載解析的唯一結果。
struct Functor { void operator()(int) const; using fptr_t = void(*)(std::nullptr_t); operator fptr_t() const; }; using Meta0 = reflexpr(Functor{}(0)); // OK // using Meta1 = reflexpr(Functor{}(nullptr)); // error: conversion function used
[編輯]
一個 *別名* 是由 typedef 宣告、別名宣告,或 using 宣告 引入的名稱。
實體或別名 B 與實體或別名 A *反射相關*,如果
-
A和B是相同的實體或別名, -
A是變數或列舉器,而B是A的類型, -
A是列舉,而B是A的底層類型, -
A是類別,而B是A的成員或基礎類別, -
A是指定實體B的非模板別名, -
A不是全域命名空間,而B是A的外圍類別或命名空間, -
A是括號表達式 (B), -
A是閉包類型B的 Lambda 捕捉, -
A是 Lambda 捕捉B的閉包類型, -
B是由 函式樣式類型轉換表達式A指定的類型, -
B是為 函式呼叫表達式A透過多載解析選定的函式,或 -
B是函式A的回傳類型、參數類型或函式類型,或 -
B與實體或別名X反射相關,且X與A反射相關。
反射關係是自反和遞移的,但不是對稱的。
非正式地說,B 與 A 反射相關的情況意味著 B 參與了 A 的宣告或定義。
將產生後設物件類型的零個或多個連續類型轉換應用於由 reflexpr-指定符 表示的類型,可以檢查與運算元反射相關的實體和別名;這樣的後設物件類型被稱為反射相應的反射相關實體或別名。
struct X; struct B { using X = ::X; typedef X Y; }; struct D : B { using B::Y; }; // ::X, but not B::X or B::Y is reflection-related to D::Y
[編輯] 其他
- 用作 reflexpr-運算元 的表達式是 未求值表達式 並 可能常數求值。
- 為了確定在 Lambda 表達式中由預設捕捉 (capture-default) 捕捉的變數,
reflexpr運算元不被視為未求值運算元。 - 由後設物件類型
T反射的靜態 儲存期 函式或變數,會被特化 std::experimental::reflect::get_pointer<T> ODR 使用,如同取得命名該函式或變數的識別碼表達式的位址一樣。 - 後設物件類型可以有多個定義,只要對此類型的所有操作都產生相同的常數表達式結果即可。
- 如果類型由 reflexpr-指定符 表示,且運算元,則類型是 依賴的
[編輯] 關鍵字
[編輯] 預定義功能測試巨集
| __cpp_reflection (反射技術規範) |
值至少為 201902 表示支援反射技術規範 (Reflection TS) (巨集常數) |
[編輯] 函式庫支援
[編輯] 概念
| 定義於標頭檔
<experimental/reflect> | |
| 定義於命名空間
std::experimental::reflect | |
| 定義於內聯命名空間
std::experimental::reflect::v1 | |
| (反射技術規範) |
指定類型為後設物件類型 (概念) |
| (反射技術規範) |
指定後設物件類型為後設物件序列類型 (概念) |
| (反射技術規範) |
指定後設物件類型反射模板參數作用域 (概念) |
| (反射技術規範) |
指定後設物件類型反射具有相關聯(可能為空)名稱的實體或別名 (概念) |
| (反射技術規範) |
指定後設物件類型反射類型別名、命名空間別名,或由 using 宣告引入的別名 (概念) |
| (反射技術規範) |
指定後設物件類型反射類別的 成員宣告 (概念) |
| (反射技術規範) |
指定後設物件類型反射列舉器 (概念) |
| (反射技術規範) |
指定後設物件類型反射變數或資料成員 (概念) |
| (反射技術規範) |
指定後設物件類型滿足 RecordMember、Enumerator 或 Variable,或反射除全域命名空間以外的命名空間(概念) |
| (反射技術規範) |
指定後設物件類型反射具有類型的實體 (概念) |
| (反射技術規範) |
指定後設物件類型反射命名空間 (概念) |
| (反射技術規範) |
指定後設物件類型反射全域命名空間 (概念) |
| (反射技術規範) |
指定後設物件類型反射非聯集類別類型 (概念) |
| (反射技術規範) |
指定後設物件類型反射列舉類型 (概念) |
| (反射技術規範) |
指定後設物件類型反射類別類型 (概念) |
| (反射技術規範) |
指定後設物件類型反射命名空間、類別、列舉、函式、閉包類型、模板參數作用域 (概念) |
| (反射技術規範) |
指定後設物件類型反射類型 (概念) |
| (反射技術規範) |
指定後設物件類型反射列舉器或 constexpr 變數 (概念) |
| (反射技術規範) |
指定後設物件類型反射從 get_base_classes 取得的直接基礎類別(概念) |
| (反射技術規範) |
指定後設物件類型反射函式參數 (概念) |
| (反射技術規範) |
指定後設物件類型反射函式(包括建構式和解構式) (概念) |
| (反射技術規範) |
指定後設物件類型反射表達式 (概念) |
| (反射技術規範) |
指定後設物件類型反射括號表達式 (概念) |
| (反射技術規範) |
指定後設物件類型反射 函式呼叫表達式 (概念) |
| (反射技術規範) |
指定後設物件類型反射 函式樣式類型轉換表達式 (概念) |
| (反射技術規範) |
指定後設物件類型反射函式(不包括建構式和解構式) (概念) |
| (反射技術規範) |
指定後設物件類型反射成員函式(不包括建構式和解構式) (概念) |
| (反射技術規範) |
指定後設物件類型反射特殊成員函式 (概念) |
| (反射技術規範) |
指定後設物件類型反射建構式 (概念) |
| (反射技術規範) |
指定後設物件類型反射解構式 (概念) |
| (反射技術規範) |
指定後設物件類型反射運算子函式或轉換函式 (概念) |
| (反射技術規範) |
指定後設物件類型反射轉換函式 (概念) |
| (反射技術規範) |
指定後設物件類型反射非泛型 Lambda 的閉包類型 (概念) |
| (反射技術規範) |
指定後設物件類型反射 Lambda 捕捉 (概念) |
[編輯] 後設物件操作
| 定義於標頭檔
<experimental/reflect> | |
| 定義於命名空間
std::experimental::reflect | |
| 定義於內聯命名空間
std::experimental::reflect::v1 | |
| |
| (反射技術規範) |
檢查兩個後設物件類型是否反射相同的實體或別名 (類別模板) |
| (反射技術規範) |
取得被反射實體或別名宣告的推定行號 (類別模板) |
| (反射技術規範) |
取得被反射實體或別名宣告的實作定義行號 (類別模板) |
| (反射技術規範) |
取得被反射實體或別名宣告的推定檔名 (類別模板) |
| |
| (反射技術規範) |
取得後設物件序列的大小 (類別模板) |
| (反射技術規範) |
取得序列中指定索引的後設物件類型 (類別模板) |
| (反射技術規範) |
將模板應用於後設物件序列 (類別模板) |
| |
| (反射技術規範) |
檢查被反射實體或別名是否不具名 (類別模板) |
| (反射技術規範) |
取得被反射實體或別名的非限定名稱 (類別模板) |
| (反射技術規範) |
取得被反射實體或別名的實作定義顯示名稱 (類別模板) |
| |
| (反射技術規範) |
取得反射被反射別名相關聯實體的後設物件類型 (類別模板) |
| |
| (反射技術規範) |
取得反射被反射實體或別名類型的後設物件類型 (類別模板) |
| (反射技術規範) |
取得被反射實體或別名的類型 (類別模板) |
| (反射技術規範) |
檢查後設物件類型是否反射列舉類型 (類別模板) |
| (反射技術規範) |
檢查後設物件類型是否反射聯集類型 (類別模板) |
| (反射技術規範) |
檢查後設物件類型是否反射宣告分別使用 class 或 struct 的非聯集類別類型 (類別模板) |
| |
| (反射技術規範) |
取得反射被反射實體或別名作用域的後設物件類型 (類別模板) |
| |
| (反射技術規範) |
取得反射給定基礎類別關係中基礎類別的後設物件類型 (類別模板) |
| |
| (反射技術規範) |
檢查被反射成員或基礎類別是否為公開 (類別模板) |
| (反射技術規範) |
檢查被反射成員或基礎類別是否為受保護 (類別模板) |
| (反射技術規範) |
檢查被反射成員或基礎類別是否為私有 (類別模板) |
| |
| 取得一個後設物件序列類型,其元素反射被反射類別的公開、可存取或所有資料成員 (類別模板) | |
| 取得一個後設物件序列類型,其元素反射被反射類別的公開、可存取或所有成員函式 (類別模板) | |
| (反射技術規範) |
取得一個後設物件序列類型,其元素反射被反射類別的所有建構式 (類別模板) |
| (反射技術規範) |
取得一個後設物件序列類型,其元素反射被反射類別中宣告的所有運算子函式和轉換函式 (類別模板) |
| (反射技術規範) |
取得反射被反射類別解構式的後設物件類型 (類別模板) |
| 取得一個後設物件序列類型,其元素反射被反射類別的公開、可存取或所有巢狀類型或成員 typedef (類別模板) | |
| 取得一個後設物件序列類型,其元素反射被反射類別的公開、可存取或所有基礎類別 (類別模板) | |
| |
| (反射技術規範) |
檢查被反射列舉是否為作用域列舉 (類別模板) |
| (反射技術規範) |
取得一個後設物件序列類型,其元素反射被反射列舉的列舉器 (類別模板) |
| (反射技術規範) |
取得反射被反射列舉底層類型的後設物件類型 (類別模板) |
| |
| (反射技術規範) |
取得作為常數表達式的被反射變數的值 (類別模板) |
| (反射技術規範) |
檢查變數是否使用 thread_local 宣告 (類別模板) |
| |
| (反射技術規範) |
檢查被反射參數是否具有預設引數 (類別模板) |
| |
| (反射技術規範) |
取得一個後設物件序列類型,其元素反射被反射函式的參數 (類別模板) |
| (反射技術規範) |
檢查被反射函式的參數清單是否包含省略符號參數 (類別模板) |
| (反射技術規範) |
檢查被反射函式是否不拋出例外 (類別模板) |
| (反射技術規範) |
檢查被反射函式是否被刪除 (類別模板) |
| |
| (反射技術規範) |
檢查被反射變數或函式是否為 constexpr (類別模板) |
| |
| (反射技術規範) |
檢查被反射命名空間或函式是否為 inline (類別模板) |
| |
| (反射技術規範) |
取得反射被反射括號表達式中未加括號表達式的後設物件類型 (類別模板) |
| |
| (反射技術規範) |
取得反射被反射 函式呼叫表達式 中函式的後設物件類型 (類別模板) |
| |
| (反射技術規範) |
取得反射被反射 函式樣式類型轉換表達式 中建構式的後設物件類型 (類別模板) |
| |
| (反射技術規範) |
取得被反射變數或函式的位址,或指向被反射非靜態成員的成員指標值 (類別模板) |
| |
| 檢查被反射成員函式是否分別使用 const、volatile、& 或 && 限定符宣告 (類別模板) | |
| (反射技術規範) |
檢查被反射成員函式是否覆寫基礎類別的成員函式 (類別模板) |
| |
| (反射技術規範) |
檢查被反射類別或成員函式是否標記為 final (類別模板) |
| |
| (反射技術規範) |
檢查被反射變數是否具有靜態儲存期,或被反射成員函式是否為靜態 (類別模板) |
| |
| (反射技術規範) |
檢查被反射特殊成員函式是否為隱式宣告 (類別模板) |
| (反射技術規範) |
檢查被反射特殊成員函式在其首次宣告中是否預設化 (類別模板) |
| |
| (反射技術規範) |
檢查被反射建構式或轉換函式是否使用 explicit 宣告 (類別模板) |
| |
| (反射技術規範) |
檢查被反射成員函式是否為虛擬 (類別模板) |
| (反射技術規範) |
檢查被反射成員函式是否為純虛擬 (類別模板) |
| |
| (反射技術規範) |
取得一個後設物件序列類型,其元素反射被反射閉包類型的捕捉 (類別模板) |
檢查被反射閉包類型的 Lambda 表達式捕捉預設是否分別為 = 或 &(類別模板) | |
| (反射技術規範) |
檢查被反射閉包類型的 operator() 是否使用 const 宣告(類別模板) |
| |
| (反射技術規範) |
檢查被反射 Lambda 捕捉是否為明確捕捉 (類別模板) |
| (反射技術規範) |
檢查被反射 Lambda 捕捉是否為初始化捕捉 (init-capture) (類別模板) |
[編輯] 函式庫功能測試巨集
| 定義於標頭檔
<experimental/reflect> | |
| __cpp_lib_reflection (反射技術規範) |
值至少為 201902 表示支援反射技術規範 (Reflection TS) 的支援函式庫 (巨集常數) |
[編輯] 概念的滿足
下表列出反射運算元的後設物件類型是否滿足反射技術規範引入的概念。
| 分類 | reflexpr 運算元 |
滿足的概念 |
|---|---|---|
| 類型 | 指定聯集的 class-name | reflect::Union
|
| 指定閉包類型的 class-name | reflect::Lambda
| |
| 指定非聯集類別的 class-name | reflect::Record
| |
| 列舉名稱 | reflect::Enum
| |
| 模板 類型參數 | reflect::Type、reflect::Alias | |
| decltype 指定符 | reflect::Type、reflect::Alias | |
| 由 using 宣告 引入的 類型名稱 | reflect::Type、reflect::Alias、reflect::ScopedMember | |
| 任何其他 typedef 名稱 | reflect::Type、reflect::Alias | |
| 任何其他 類型識別碼 | reflect::Type
| |
| 命名空間 | 命名空間別名 | reflect::Namespace、reflect::Alias |
| 全域命名空間 | reflect::GlobalScope
| |
| 任何其他 命名空間 | reflect::Namespace
| |
| 表達式 | 資料成員的名稱 | reflect::Variable
|
| 變數的名稱 | reflect::Variable
| |
| 列舉器的名稱 | reflect::Enumerator
| |
| 函式參數的名稱 | reflect::FunctionParameter
| |
| 被捕捉實體的名稱 | reflect::LambdaCapture
| |
| 括號表達式 | reflect::ParenthesizedExpression
| |
| 函式呼叫表達式 | reflect::FunctionCallExpression
| |
| 函式樣式類型轉換表達式 | reflect::FunctionalTypeConversion
|
如果 `識別碼表達式` 形式的運算元是常數表達式,則由 reflexpr-指定符 指定的類型也滿足 reflect::Constant。
如果 `reflexpr-運算元` 指定一個類別成員,則由 reflexpr-指定符 表示的類型也滿足 reflect::RecordMember。
[編輯] 參見
| 包含某些類型資訊,由 typeid 運算子回傳的類別 (類別) | |
| (C++11) |
編譯時類型資訊公用程式 |