名稱空間
變體
操作

requires 表示式 (C++20 起)

來自 cppreference.com
< cpp‎ | 語言
 
 
C++ 語言
 
 
 
 

生成一個描述約束的 bool 型別的純右值表示式。

目錄

[編輯] 語法

requires { requirement-seq } (1)
requires ( parameter-list (可選) ) { requirement-seq } (2)
parameter-list - 一個引數列表
requirement-seq - 一系列需求,每個需求是下列之一

[編輯] 解釋

需求可以引用作用域內的模板引數、parameter-list 的引數,以及從封閉上下文可見的任何其他宣告。

將模板實參替換到用於模板化實體宣告中的 requires 表示式中,可能會導致其需求中形成無效型別或表示式,或違反這些需求的語義約束。在這種情況下,requires 表示式評估為 false,並且不會導致程式格式錯誤。替換和語義約束檢查按詞法順序進行,並在遇到確定 requires 表示式結果的條件時停止。如果替換(如果有)和語義約束檢查成功,則 requires 表示式評估為 true

如果在 requires 表示式中,對於每個可能的模板實參都會發生替換失敗,則程式格式錯誤,無需診斷。

template<class T>
concept C = requires
{
    new int[-(int)sizeof(T)]; // invalid for every T: ill-formed, no diagnostic required
};

如果 requires 表示式在其需求中包含無效型別或表示式,並且它沒有出現在模板化實體的宣告中,則程式格式錯誤。

[編輯] 區域性引數

一個 requires 表示式可以使用引數列表引入區域性引數。這些引數沒有連結、儲存或生命週期;它們僅用作定義需求的符號。

每個引數的型別以與確定函式引數的實際型別相同的方式確定。

template<typename T>
concept C = requires(T p[2])
{
    (decltype(p))nullptr; // OK, p has type T*
};

如果滿足以下任何條件,程式將不正確:

  • 區域性引數具有預設實參
  • 引數列表以省略號結尾。
template<typename T>
concept C1 = requires(T t = 0)  // Error: t has a default argument
{
    t;
};
 
template<typename T>
concept C2 = requires(T t, ...) // Error: terminates with an ellipsis
{
    t;
};

[編輯] 簡單需求

expression ;
表示式 - 一個不以 requires 開頭的表示式


一個簡單需求斷言 expression 是有效的。expression 是一個未求值運算元

template<typename T>
concept Addable = requires (T a, T b)
{
    a + b; // "the expression “a + b” is a valid expression that will compile"
};
 
template<class T, class U = T>
concept Swappable = requires(T&& t, U&& u)
{
    swap(std::forward<T>(t), std::forward<U>(u));
    swap(std::forward<U>(u), std::forward<T>(t));
};

以關鍵詞 requires 開頭的需求總是被解釋為巢狀需求。因此,簡單需求不能以不帶括號的 requires 表示式開頭。

[編輯] 型別需求

typename identifier ;
identifier - 一個(可能帶限定的)識別符號(包括簡單模板識別符號


型別需求斷言由 identifier 命名的型別是有效的:這可以用於驗證某個命名的巢狀型別是否存在,或者類/別名模板特化是否命名了一個型別。命名類模板特化的型別需求不要求型別是完整的。

template<typename T>
using Ref = T&;
 
template<typename T>
concept C = requires
{
    typename T::inner; // required nested member name
    typename S<T>;     // required class template specialization
    typename Ref<T>;   // required alias template substitution
};
 
template<class T, class U>
using CommonType = std::common_type_t<T, U>;
 
template<class T, class U>
concept Common = requires (T&& t, U&& u)
{
    typename CommonType<T, U>; // CommonType<T, U> is valid and names a type
    { CommonType<T, U>{std::forward<T>(t)} }; 
    { CommonType<T, U>{std::forward<U>(u)} }; 
};

[編輯] 複合需求

{ expression }; (1)
{ expression } noexcept ; (2)
{ expression } -> type-constraint ; (3)
{ expression } noexcept -> type-constraint ; (4)
表示式 - 一個表示式
type-constraint - 一個約束


複合需求斷言 expression 的屬性。替換和語義約束檢查按以下順序進行:

1) 模板實參(如果有)被替換到 expression 中。
2) 如果存在 noexcept,則 expression 不得是可能丟擲異常的
3) 如果存在 type-constraint,則
a) 模板實參被替換到 type-constraint 中。
b) decltype((expression )) 必須滿足 type-constraint 施加的約束。否則,封閉的 requires 表示式為 false

expression 是一個未求值運算元

template<typename T>
concept C2 = requires(T x)
{
    // the expression *x must be valid
    // AND the type T::inner must be valid
    // AND the result of *x must be convertible to T::inner
    {*x} -> std::convertible_to<typename T::inner>;
 
    // the expression x + 1 must be valid
    // AND std::same_as<decltype((x + 1)), int> must be satisfied
    // i.e., (x + 1) must be a prvalue of type int
    {x + 1} -> std::same_as<int>;
 
    // the expression x * 1 must be valid
    // AND its result must be convertible to T
    {x * 1} -> std::convertible_to<T>;
};

[編輯] 巢狀需求

requires constraint-expression ;
constraint-expression - 表示約束的表示式


巢狀需求可用於根據區域性引數指定額外約束。constraint-expression 必須由替換的模板實參(如果有)滿足。將模板實參替換到巢狀需求中,僅在確定 constraint-expression 是否滿足所需的程度上,才會替換到 constraint-expression 中。

template<class T>
concept Semiregular = DefaultConstructible<T> &&
    CopyConstructible<T> && CopyAssignable<T> && Destructible<T> &&
requires(T a, std::size_t n)
{  
    requires Same<T*, decltype(&a)>; // nested: "Same<...> evaluates to true"
    { a.~T() } noexcept; // compound: "a.~T()" is a valid expression that doesn't throw
    requires Same<T*, decltype(new T)>; // nested: "Same<...> evaluates to true"
    requires Same<T*, decltype(new T[n])>; // nested
    { delete new T }; // compound
    { delete new T[n] }; // compound
};

[編輯] 注意

關鍵詞 requires 也用於引入requires 子句

template<typename T>
concept Addable = requires (T x) { x + x; }; // requires expression
 
template<typename T> requires Addable<T> // requires clause, not requires expression
T add(T a, T b) { return a + b; }
 
template<typename T>
    requires requires (T x) { x + x; } // ad-hoc constraint, note keyword used twice
T add(T a, T b) { return a + b; }

[編輯] 關鍵詞

requires

[編輯] 缺陷報告

下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。

缺陷報告 應用於 釋出時的行為 正確的行為
CWG 2560 C++20 引數型別在 requires 表示式中是否被調整尚不明確 也已調整
CWG 2911 C++20 出現在 requires 中的所有表示式
表示式都是未求值運算元
只有一些
表示式是

[編輯] 參考資料

  • C++23 標準 (ISO/IEC 14882:2024)
  • 7.5.7 Requires 表示式 [expr.prim.req]
  • C++20 標準 (ISO/IEC 14882:2020)
  • 7.5.7 Requires 表示式 [expr.prim.req]

[編輯] 另請參閱

約束和概念(C++20) 指定對模板實參的要求[編輯]