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 1:
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 3:
template<typename T> concept C =
requires {
new decltype(void)T{});
};
—
end example]
[
Example 1:
template<typename T> concept C =
requires (T a, T b) {
a + b;
};
—
end example]
[
Note 1:
The enclosing
requires-expression will evaluate to
false
if substitution of template arguments fails. —
end note]
[
Example 1:
template<typename T, typename T::type = 0> struct S;
template<typename T> using Ref = T&;
template<typename T> concept C = requires {
typename T::inner;
typename S<T>;
typename Ref<T>;
typename [:T::r1:];
typename [:T::r2:]<int>;
};
—
end example]
Substitution
of template arguments (if any) and verification of
semantic properties proceed in the following order:
Substitution of template arguments (if any)
into the
expression is performed
.If the
noexcept specifier is present,
E shall not be a potentially-throwing expression ([except.spec]).If the
return-type-requirement is present, then:
-
[
Example 1:
Given concepts
C and
D,
requires {
{ E1 } -> C;
{ E2 } -> D<A1, ⋯, An>;
};
is equivalent to
requires {
E1; requires C<decltype(E1))>;
E2; requires D<decltype(E2)), A1, ⋯, An>;
};
(including in the case where n is zero). —
end example]
[
Example 2:
template<typename T> concept C1 = requires(T x) {
{x++};
};
template<typename T> concept C2 = requires(T x) {
{*x} -> std::same_as<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
std::same_as<decltype(*x)), typename T::inner> is satisfied
.template<typename T> concept C3 =
requires(T x) {
{g(x)} noexcept;
};
A
nested-requirement can be used
to specify additional constraints in terms of local parameters
. [
Example 1:
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]