7 Expressions [expr]

7.5 Primary expressions [expr.prim]

7.5.7 Requires expressions [expr.prim.req]

A requires-expression provides a concise way to express requirements on template arguments that can be checked by name lookup or by checking properties of types and expressions.
requires-expression:
	requires requirement-parameter-list requirement-body
requirement-parameter-list:
	( parameter-declaration-clause )
requirement-body:
	{ requirement-seq }
requirement-seq:
	requirement
	requirement-seq requirement
requirement:
	simple-requirement
	type-requirement
	compound-requirement
	nested-requirement
A requires-expression is a prvalue of type bool whose value is described below.
Expressions appearing within a requirement-body are unevaluated operands.
[Example
:
A common use of requires-expressions is to define requirements in concepts such as the one below:
template<typename T>
  concept R = requires (T i) {
    typename T::type;
    {*i} -> const typename T::type&;
  };
A requires-expression can also be used in a requires-clause as a way of writing ad hoc constraints on template arguments such as the one below:
template<typename T>
  requires requires (T x) { x + x; }
    T add(T a, T b) { return a + b; }
The first requires introduces the requires-clause, and the second introduces the requires-expression.
end example
]
A requires-expression may introduce local parameters using a parameter-declaration-clause.
A local parameter of a requires-expression shall not have a default argument.
Each name introduced by a local parameter is in scope from the point of its declaration until the closing brace of the requirement-body.
These parameters have no linkage, storage, or lifetime; they are only used as notation for the purpose of defining requirements.
The parameter-declaration-clause of a requirement-parameter-list shall not terminate with an ellipsis.
[Example
:
template<typename T>
concept C = requires(T t, ...) {    // error: terminates with an ellipsis
  t;
};
end example
]
The requirement-body contains a sequence of requirements.
These requirements may refer to local parameters, template parameters, and any other declarations visible from the enclosing context.
The substitution of template arguments into a requires-expression may result in the formation of invalid types or expressions in its requirements or the violation of the semantic constraints of those requirements.
In such cases, the requires-expression evaluates to false; it 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.
[Note
:
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.
end note
]
If the substitution of template arguments into a requirement would always result in a substitution failure, the program is ill-formed; no diagnostic required.
[Example
:
template<typename T> concept C =
requires {
  new int[-(int)sizeof(T)]; // ill-formed, no diagnostic required
};
end example
]

7.5.7.1 Simple requirements [expr.prim.req.simple]

simple-requirement:
	expression ;
A simple-requirement asserts the validity of an expression.
[Note
:
The enclosing requires-expression will evaluate to false if substitution of template arguments into the expression fails.
end note
]
[Example
:
template<typename T> concept C =
  requires (T a, T b) {
    a + b;  // C<T> is true if a + b is a valid expression
  };
end example
]

7.5.7.2 Type requirements [expr.prim.req.type]

type-requirement:
	typename nested-name-specifier type-name ;
A type-requirement asserts the validity of a type.
[Note
:
The enclosing requires-expression will evaluate to false if substitution of template arguments fails.
end note
]
[Example
:
template<typename T, typename T::type = 0> struct S;
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, fails if T is void
};
end example
]
A type-requirement that names a class template specialization does not require that type to be complete ([basic.types]).

7.5.7.3 Compound requirements [expr.prim.req.compound]

compound-requirement:
	{ expression } noexcept return-type-requirement ;
return-type-requirement:
	trailing-return-type
	-> cv-qualifier-seq constrained-parameter cv-qualifier-seq abstract-declarator
A compound-requirement asserts properties of the expression E.
Substitution of template arguments (if any) and verification of semantic properties proceed in the following order:
[Example
:
template<typename T> concept C1 = requires(T x) {
  {x++};
};
The compound-requirement in C1 requires that x++ is a valid expression.
It is equivalent to the simple-requirement x++;.
template<typename T> concept C2 = requires(T x) {
  {*x} -> typename T::inner;
};
The compound-requirement in C2 requires that *x is a valid expression, that typename T​::​inner is a valid type, and that *x is implicitly convertible to typename T​::​inner.
template<typename T, typename U> concept C3 = requires (T t, U u) {
  t == u;
};
template<typename T> concept C4 = requires(T x) {
  {*x} -> C3<int> const&;
};
The compound-requirement requires that *x be deduced as an argument for the invented function:
template<C3<int> X> void f(X const&);
In this case, deduction only succeeds if an expression of the type deduced for X can be compared to an int with the == operator.
template<typename T> concept C5 =
  requires(T x) {
    {g(x)} noexcept;
  };
The compound-requirement in C5 requires that g(x) is a valid expression and that g(x) is non-throwing.
end example
]

7.5.7.4 Nested requirements [expr.prim.req.nested]

nested-requirement:
	requires constraint-expression ;
A nested-requirement can be used to specify additional constraints in terms of local parameters.
The constraint-expression shall be satisfied ([temp.constr.decl]) by the substituted template arguments, if any.
Substitution of template arguments into a nested-requirement does not result in substitution into the constraint-expression other than as specified in [temp.constr.decl].
[Example
:
template<typename U> concept C = sizeof(U) == 1;

template<typename T> concept D = requires (T t) {
  requires C<decltype (+t)>;
};
D<T> is satisfied if sizeof(decltype (+t)) == 1 ([temp.constr.atomic]).
end example
]
A local parameter shall only appear as an unevaluated operand within the constraint-expression.
[Example
:
template<typename T> concept C = requires (T a) {
  requires sizeof(a) == 4;  // OK
  requires a == 0;          // error: evaluation of a constraint variable
}
end example
]