Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/language/requires"

From cppreference.com
< cpp‎ | language
m (Compound Requirements: fmt)
(+References)
 
(6 intermediate revisions by 5 users not shown)
Line 1: Line 1:
 
{{title|Requires expression {{mark since c++20}}}}
 
{{title|Requires expression {{mark since c++20}}}}
{{cpp/language/templates/navbar}}
+
{{cpp/language/declarations/expressions/templates/navbar}}
  
 
+
Yields a prvalue expression of type {{c/core|bool}} that describes the constraints.  
Yields a prvalue expression of type {{c|bool}} that describes the constraints.  
+
  
 
===Syntax===
 
===Syntax===
 
{{sdsc begin}}
 
{{sdsc begin}}
{{sdsc|{{ttb|requires}} {{ttb|{<!---->}} {{spar|requirement-seq}} {{ttb|}<!---->}}}}
+
{{sdsc|num=1|{{ttb|requires}} {{ttb|{<!---->}} {{spar|requirement-seq}} {{ttb|}<!---->}}}}
{{sdsc|{{ttb|requires}} {{ttb|(}} {{spar optional|parameter-list}} {{ttb|)}} {{ttb|{<!---->}} {{spar|requirement-seq}} {{ttb|}<!---->}}}}
+
{{sdsc|num=2|{{ttb|requires}} {{ttb|(}} {{spar optional|parameter-list}} {{ttb|)}} {{ttb|{<!---->}} {{spar|requirement-seq}} {{ttb|}<!---->}}}}
 
{{sdsc end}}
 
{{sdsc end}}
 
{{par begin}}
 
{{par begin}}
{{par|{{spar|parameter-list}}|a comma-separated list of parameters like in a function declaration, except that default arguments are not allowed and it cannot end with an ellipsis (other than one signifying a pack expansion). These parameters have no storage, linkage or lifetime, and are only used to assist in specifying requirements. These parameters are in scope until the closing {{ttb|}<!---->}} of the {{spar|requirement-seq}}.}}
+
{{par|{{spar|parameter-list}}|a {{rlpsd|function#Parameter list}}}}
 
{{par|{{spar|requirement-seq}}|sequence of ''requirements'', each requirement is one of the following:
 
{{par|{{spar|requirement-seq}}|sequence of ''requirements'', each requirement is one of the following:
* simple requirement
+
* [[#Simple requirements|simple requirement]]
* type requirements
+
* [[#Type requirements|type requirement]]
* compound requirements
+
* [[#Compound requirements|compound requirement]]
* nested requirements}}
+
* [[#Nested requirements|nested requirement]]}}
 
{{par end}}
 
{{par end}}
  
 
===Explanation===
 
===Explanation===
 +
Requirements may refer to the template parameters that are in scope, to the parameters of {{spar|parameter-list}}, and to any other declarations that are visible from the enclosing context.
  
Requirements may refer to the template parameters that are in scope, to the local parameters introduced in the {{spar|parameter-list}}, and to any other declarations that are visible from the enclosing context.
+
The substitution of template arguments into a requires-expression used in a declaration of a {{rlpsd|templates#Templated entity}} may result in the formation
 
+
The substitution of template arguments into a requires-expression used in a declaration of a {{rlp|templates#Templated_entity|templated entity}} may result in the formation
+
 
of invalid types or expressions in its requirements, or the violation of semantic constraints of those requirements. In such cases, the requires-expression evaluates to {{c|false}} and does not cause the program to be ill-formed. The substitution and semantic constraint checking proceeds in lexical order and stops when a condition that determines the result of the requires-expression is encountered. If substitution (if any) and semantic constraint checking succeed, the requires-expression evaluates to {{c|true}}.
 
of invalid types or expressions in its requirements, or the violation of semantic constraints of those requirements. In such cases, the requires-expression evaluates to {{c|false}} and does not cause the program to be ill-formed. The substitution and semantic constraint checking proceeds in lexical order and stops when a condition that determines the result of the requires-expression is encountered. If substitution (if any) and semantic constraint checking succeed, the requires-expression evaluates to {{c|true}}.
  
Line 35: Line 33:
 
}}
 
}}
  
If a requires-expression contains invalid types or expressions in its requirements, and it does not appear within the declaration of a {{rlp|templates#Templated_entity|templated entity}}, then the program is ill-formed.
+
If a requires-expression contains invalid types or expressions in its requirements, and it does not appear within the declaration of a {{rlpsd|templates#Templated entity}}, then the program is ill-formed.
  
===Simple requirements===
+
===Local parameters===
A simple requirement is an arbitrary expression statement that does not start with the keyword {{tt|requires}}. It asserts that the expression is valid. The expression is an unevaluated operand; only language correctness is checked.
+
A requires-expression can introduce local parameters using a {{rlpsd|function#Parameter list}}. These parameters have no linkage, storage, or lifetime; they are only used as notation for the purpose of defining requirements.
 +
 
 +
The type of each parameter is determined by the same way as {{rlp|function#Function type|determining the actual type}} of function parameters:
 +
{{source|1=
 +
template<typename T>
 +
concept C = requires(T p[2])
 +
{
 +
    (decltype(p))nullptr; // OK, p has type T*
 +
};
 +
}}
 +
 
 +
If any of the following conditions is satisfied, the program is ill-formed:
 +
* A local parameter has a {{rlp|default arguments|default argument}}.
 +
* The parameter list terminate with an ellipsis.
 +
{{source|1=
 +
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;
 +
};
 +
}}
 +
 
 +
===Requirements===
 +
====Simple requirements====
 +
A simple requirement is an arbitrary expression statement that does not start with the keyword {{c/core|requires}}. It asserts that the expression is valid. The expression is an unevaluated operand; only language correctness is checked.
  
 
{{source|1=
 
{{source|1=
Line 44: Line 72:
 
concept Addable = requires (T a, T b)
 
concept Addable = requires (T a, T b)
 
{
 
{
     a + b; // "the expression a+b is a valid expression that will compile"
+
     a + b; // "the expression “a + b” is a valid expression that will compile"
 
};
 
};
  
Line 55: Line 83:
 
}}
 
}}
  
A requirement that starts with the keyword {{tt|requires}} is always interpreted as a nested requirement. Thus a simple requirement cannot start with an unparenthesized requires-expression.
+
A requirement that starts with the keyword {{c/core|requires}} is always interpreted as a nested requirement. Thus a simple requirement cannot start with an unparenthesized requires-expression.
  
===Type requirements===
+
====Type requirements====
A type requirement is the keyword {{c|typename}} followed by a type name, optionally qualified. The requirement is that the named type is valid: this can be used to verify that a certain named nested type exists, or that a class template specialization names a type, or that an alias template specialization names a type. A type requirement naming a class template specialization does not require the type to be complete.
+
A type requirement is the keyword {{ltt|cpp/keyword/typename}} followed by a type name, optionally qualified. The requirement is that the named type is valid: this can be used to verify that a certain named nested type exists, or that a class template specialization names a type, or that an alias template specialization names a type. A type requirement naming a class template specialization does not require the type to be complete.
  
 
{{source|1=
 
{{source|1=
Line 84: Line 112:
 
}}
 
}}
  
===Compound Requirements===
+
====Compound requirements====
 
A compound requirement has the form  
 
A compound requirement has the form  
 
{{sdsc begin}}
 
{{sdsc begin}}
Line 96: Line 124:
 
and asserts properties of the named expression. Substitution and semantic constraint checking proceeds in the following order:
 
and asserts properties of the named expression. Substitution and semantic constraint checking proceeds in the following order:
 
@1@ Template arguments (if any) are substituted into {{spar|expression}};
 
@1@ Template arguments (if any) are substituted into {{spar|expression}};
@2@ If {{tt|noexcept}} is used, {{spar|expression}} must not be [[cpp/language/noexcept|potentially throwing]];
+
@2@ If {{c/core|noexcept}} is used, {{spar|expression}} must not be [[cpp/language/noexcept|potentially throwing]];
 
@3@ If {{spar|return-type-requirement}} is present, then:
 
@3@ If {{spar|return-type-requirement}} is present, then:
:@a@ Template arguments are substituted into the {{spar|return-type-requirement}};
+
:@a@ Template arguments are substituted into the {{spar sep|return-type-requirement}};
:@b@ {{c|decltype((expression))}} must satisfy the constraint imposed by the {{spar|type-constraint}}. Otherwise, the enclosing requires-expression is {{c|false}}.
+
:@b@ {{c/core|decltype((expression))}} must satisfy the constraint imposed by the {{spar|type-constraint}}. Otherwise, the enclosing requires-expression is {{c|false}}.
  
 
{{source|1=
 
{{source|1=
Line 121: Line 149:
 
}}
 
}}
  
===Nested requirements===
+
====Nested requirements====
 
A nested requirement has the form  
 
A nested requirement has the form  
 
{{sdsc begin}}
 
{{sdsc begin}}
{{sdsc| {{ttb|requires}} {{spar|constraint-expression}} {{ttb|;}} }}
+
{{sdsc|{{ttb|requires}} {{spar|constraint-expression}} {{ttb|;}} }}
 
{{sdsc end}}
 
{{sdsc end}}
  
Line 145: Line 173:
  
 
===Note===
 
===Note===
 
+
The keyword {{c/core|requires}} is also used to introduce {{lsd|cpp/language/constraints#Requires clauses}}.
The keyword {{c|requires}} is also used to introduce [[cpp/language/constraints#Requires clauses|requires clauses]].
+
  
 
{{source|1=
 
{{source|1=
Line 162: Line 189:
 
===Keywords===
 
===Keywords===
 
{{ltt|cpp/keyword/requires}}
 
{{ltt|cpp/keyword/requires}}
 +
 +
===Defect reports===
 +
{{dr list begin}}
 +
{{dr list item|wg=cwg|dr=2560|std=C++20|before=it was unclear whether parameter types are adjusted in requires-expressions|after=also adjusted}}
 +
{{dr list end}}
 +
 +
===References===
 +
{{ref std c++23}}
 +
{{ref std|section=7.5.7|title=Requires expressions|id=expr.prim.req}}
 +
{{ref std end}}
 +
{{ref std c++20}}
 +
{{ref std|section=7.5.7|title=Requires expressions|id=expr.prim.req}}
 +
{{ref std end}}
  
 
===See also===
 
===See also===
 
{{dsc begin}}
 
{{dsc begin}}
{{dsc inc | cpp/language/dsc constraints}}
+
{{dsc inc|cpp/language/dsc constraints}}
 
{{dsc end}}
 
{{dsc end}}
  
{{langlinks|ru|zh}}
+
{{langlinks|es|ru|zh}}

Latest revision as of 00:30, 14 August 2024

 
 
C++ language
General topics
Flow control
Conditional execution statements
if
Iteration statements (loops)
for
range-for (C++11)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications (until C++17*)
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
explicit (C++11)
static

Special member functions
Templates
Miscellaneous
 
 
 
 

Yields a prvalue expression of type bool that describes the constraints.

Contents

[edit] Syntax

requires { requirement-seq } (1)
requires ( parameter-list (optional) ) { requirement-seq } (2)
parameter-list - a parameter list
requirement-seq - sequence of requirements, each requirement is one of the following:

[edit] Explanation

Requirements may refer to the template parameters that are in scope, to the parameters of parameter-list, and to any other declarations that are visible from the enclosing context.

The substitution of template arguments into a requires-expression used in a declaration of a templated entity may result in the formation of invalid types or expressions in its requirements, or the violation of semantic constraints of those requirements. In such cases, the requires-expression evaluates to false and does not cause the program to be ill-formed. The substitution and semantic constraint checking proceeds in lexical order and stops when a condition that determines the result of the requires-expression is encountered. If substitution (if any) and semantic constraint checking succeed, the requires-expression evaluates to true.

If a substitution failure would occur in a requires-expression for every possible template argument, the program is ill-formed, no diagnostic required:

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

If a requires-expression contains invalid types or expressions in its requirements, and it does not appear within the declaration of a templated entity, then the program is ill-formed.

[edit] Local parameters

A requires-expression can introduce local parameters using a parameter list. These parameters have no linkage, storage, or lifetime; they are only used as notation for the purpose of defining requirements.

The type of each parameter is determined by the same way as determining the actual type of function parameters:

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

If any of the following conditions is satisfied, the program is ill-formed:

  • A local parameter has a default argument.
  • The parameter list terminate with an ellipsis.
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;
};

[edit] Requirements

[edit] Simple requirements

A simple requirement is an arbitrary expression statement that does not start with the keyword requires. It asserts that the expression is valid. The expression is an unevaluated operand; only language correctness is checked.

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));
};

A requirement that starts with the keyword requires is always interpreted as a nested requirement. Thus a simple requirement cannot start with an unparenthesized requires-expression.

[edit] Type requirements

A type requirement is the keyword typename followed by a type name, optionally qualified. The requirement is that the named type is valid: this can be used to verify that a certain named nested type exists, or that a class template specialization names a type, or that an alias template specialization names a type. A type requirement naming a class template specialization does not require the type to be complete.

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)} }; 
};

[edit] Compound requirements

A compound requirement has the form

{ expression } noexcept(optional) return-type-requirement (optional) ;
return-type-requirement - -> type-constraint

and asserts properties of the named expression. Substitution and semantic constraint checking proceeds in the following order:

1) Template arguments (if any) are substituted into expression;
2) If noexcept is used, expression must not be potentially throwing;
3) If return-type-requirement is present, then:
a) Template arguments are substituted into the return-type-requirement ;
b) decltype((expression)) must satisfy the constraint imposed by the type-constraint. Otherwise, the enclosing requires-expression is false.
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>;
};

[edit] Nested requirements

A nested requirement has the form

requires constraint-expression ;

It can be used to specify additional constraints in terms of local parameters. The constraint-expression must be satisfied by the substituted template arguments, if any. Substitution of template arguments into a nested requirement causes substitution into the constraint-expression only to the extent needed to determine whether the constraint-expression is satisfied.

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
};

[edit] Note

The keyword requires is also used to introduce requires clauses.

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; }

[edit] Keywords

requires

[edit] Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior
CWG 2560 C++20 it was unclear whether parameter types are adjusted in requires-expressions also adjusted

[edit] References

  • C++23 standard (ISO/IEC 14882:2024):
  • 7.5.7 Requires expressions [expr.prim.req]
  • C++20 standard (ISO/IEC 14882:2020):
  • 7.5.7 Requires expressions [expr.prim.req]

[edit] See also

Constraints and concepts(C++20) specifies the requirements on template arguments[edit]