概念庫 (C++20 起)
概念庫提供了基礎程式庫概念的定義,可用於執行範本參數的編譯期驗證,並根據型別的屬性執行函式派送。這些概念為程式中的等式推理(equational reasoning)提供了基礎。
標準程式庫中的大多數概念對語法和語意都有要求。如果滿足了語法要求,則稱一個標準概念被「滿足」(satisfied);如果滿足了語法要求且其語意要求(若有)也得到滿足,則稱該概念被「模型化」(modeled)。
通常情況下,編譯器只能檢查語法要求。如果程式的正確性或意義取決於一系列範本參數是否模型化了某個概念,而該概念被滿足但未被模型化,或者在使用點未滿足某個語意要求,則程式格式錯誤,且無需診斷。
目錄 |
[編輯] 等式保持
若一個運算式在給定相等輸入時產生相等的輸出,則稱該運算式為「等式保持」,其中
- 輸入由其運算元組成(不一定使該運算式在語意上有效),且
- 輸出由其結果以及該運算式對運算元(若有)所作的所有修改組成
為方便起見,其「運算元」指代其最大的子運算式,這些子運算式由 識別碼運算式 (id-expression),或是對 std::move、std::forward 與 std::declval 的呼叫組成。
每個運算元的 cv 限定符與值類別,是假設其型別中的每個範本型別參數均表示為 cv 無限定的完整非陣列物件型別來確定的。
每個要求等式保持的運算式,也要求是穩定的(stable);即,以相同輸入物件對其進行兩次求值必須產生相等的輸出,且期間不對這些輸入物件進行任何顯式的介入修改。
除非另有說明,否則在 requires 運算式 中使用的每個 標準程式庫概念 中的運算式,都要求是等式保持的,且該運算式的求值僅能修改其非 const 運算元。常數運算元不得被修改。
在標準程式庫中,下列概念允許擁有非等式保持的 requires 運算式:
[編輯] 隱式運算式變體
對於某些常數左值運算元,若一個 requires 運算式 使用了該運算元且是非修改性的,則該運算式還隱式要求了該運算式的額外變體,這些變體接受該運算元的非 const 左值或(可能是常數的)右值,除非此類運算式變體在有不同語意的情況下被顯式要求。
這些「隱式運算式變體」必須滿足宣告運算式的相同語意要求。實作驗證這些變體語法的程度是未指定的。
template<class T> concept C = requires(T a, T b, const T c, const T d) { c == d; // expression #1: does not modify the operands a = std::move(b); // expression #2: modifies both operands a = c; // expression #3: modifies the left operand `a` }; // Expression #1 implicitly requires additional expression variations that // meet the requirements for c == d (including non-modification), // as if the following expressions had been declared as well: // ------ const == const ------- ------ const == non-const --- // c == b; // c == std::move(d); c == std::move(b); // std::move(c) == d; std::move(c) == b; // std::move(c) == std::move(d); std::move(c) == std::move(b); // -- non-const == const ------- -- non-const == non-const --- // a == d; a == b; // a == std::move(d); a == std::move(b); // std::move(a) == d; std::move(a) == b; // std::move(a) == std::move(d); std::move(a) == std::move(b); // Expression #3 implicitly requires additional expression variations that // meet the requirements for a = c // (including non-modification of the second operand), // as if the expressions a = b (non-constant lvalue variation) // and a = std::move(c) (const rvalue variation) had been declared. // Note: Since expression #2 already requires the non-constant rvalue variation // (a == std::move(b)) explicitly, expression #3 does not implicitly require it anymore. // The type T meets the explicitly stated syntactic requirements of // concept C above, but does not meet the additional implicit requirements // (i.e., T satisfies but does not model C): // a program requires C<T> is ill-formed (no diagnostic required). struct T { bool operator==(const T&) const { return true; } bool operator==(T&) = delete; };
[編輯] 標準程式庫概念
| 定義於命名空間
std | |
核心語言概念 | |
| 定義於標頭
<concepts> | |
| (C++20) |
指定一個型別與另一個型別相同 (概念) |
| (C++20) |
指定一個型別衍生自另一個型別 (概念) |
| (C++20) |
指定一個型別可以隱式轉換為另一個型別 (概念) |
| (C++20) |
指定兩個型別共享一個共通參照型別 (概念) |
| (C++20) |
指定兩個型別共享一個共通型別 (概念) |
| (C++20) |
指定一個型別為整數型別 (概念) |
| (C++20) |
指定一個型別為有號整數型別 (概念) |
| (C++20) |
指定型別為無符號(unsigned)的整數型別 (概念) |
| (C++20) |
指定型別為浮點型別 (概念) |
| (C++20) |
指定一個型別可從另一個型別賦值 (概念) |
| (C++20) |
指定一個型別可以被交換,或者兩個型別可以彼此交換 (概念) |
| (C++20) |
指定該型別的物件可以被銷毀 (概念) |
| (C++20) |
指定該型別的變數可以從一組參數型別進行建構或與其綁定 (概念) |
| (C++20) |
指定該型別的物件可以進行預設建構 (概念) |
| (C++20) |
指定該型別的物件可以進行移動建構 (概念) |
| (C++20) |
指定該型別的物件可以進行複製建構與移動建構 (概念) |
比較概念 | |
| 定義於標頭
<concepts> | |
| (C++20) |
指定一個型別可用於布林上下文中 (僅供說明概念*) |
| 指定運算子 == 是一個等價關係 (概念) | |
| 指定該型別上的比較運算子產生一個全序關係 (total order) (概念) | |
| 定義於標頭
<compare> | |
| 指定運算子 <=> 在給定型別上產生一致的結果 (概念) | |
物件概念 | |
| 定義於標頭
<concepts> | |
| (C++20) |
指定該型別的物件可以被移動與交換 (概念) |
| (C++20) |
指定該型別的物件可以被複製、移動與交換 (概念) |
| (C++20) |
指定該型別的物件可以被複製、移動、交換與預設建構 (概念) |
| (C++20) |
指定型別為 regular 的,即它既是 semiregular 又是 equality_comparable(概念) |
可呼叫概念 | |
| 定義於標頭
<concepts> | |
| (C++20) |
指定一個可呼叫型別可以使用給定的一組參數型別進行呼叫 (概念) |
| (C++20) |
指定一個可呼叫型別為布林謂詞 (Boolean predicate) (概念) |
| (C++20) |
指定一個可呼叫型別為二元關係 (binary relation) (概念) |
| (C++20) |
指定一個 relation 強制要求等價關係(概念) |
| (C++20) |
指定一個 relation 強制要求嚴格弱序(概念) |
更多概念可在 迭代器程式庫、演算法程式庫 與 範圍程式庫 (ranges library) 中找到。