13 Templates [temp]

13.4 Template constraints [temp.constr]

13.4.1 Constraints [temp.constr.constr]

13.4.1.2 Atomic constraints [temp.constr.atomic]

An atomic constraint is formed from an expression E and a mapping from the template parameters that appear within E to template arguments involving the template parameters of the constrained entity, called the parameter mapping ([temp.constr.decl]).
Note
:
Atomic constraints are formed by constraint normalization.
— end note
 ]
Two atomic constraints are identical if they are formed from the same expression and the targets of the parameter mappings are equivalent according to the rules for expressions described in [temp.over.link].
To determine if an atomic constraint is satisfied, the parameter mapping and template arguments are first substituted into its expression.
If substitution results in an invalid type or expression, the constraint is not satisfied.
Otherwise, the lvalue-to-rvalue conversion is performed if necessary, and E shall be a constant expression of type bool.
The constraint is satisfied if and only if evaluation of E results in true.
Example
:
template<typename T> concept C =
  sizeof(T) == 4 && !true;      // requires atomic constraints sizeof(T) == 4 and !true

template<typename T> struct S {
  constexpr operator bool() const { return true; }
};

template<typename T> requires (S<T>{})
void f(T);                      // #1
void f(int);                    // #2

void g() {
  f(0);                         // error: expression S<int>{} does not have type bool
}                               // while checking satisfaction of deduced arguments of #1;
                                // call is ill-formed even though #2 is a better match
— end example
 ]