12 Templates [temp]

12.4 Template constraints [temp.constr]

12.4.3 Constraint normalization [temp.constr.normal]

The normal form of an expression E is a constraint that is defined as follows:
  • The normal form of an expression ( E ) is the normal form of E.
  • The normal form of an expression E1 || E2 is the disjunction of the normal forms of E1 and E2.
  • The normal form of an expression E1 && E2 is the conjunction of the normal forms of E1 and E2.
  • The normal form of an id-expression of the form C<A, A, ..., A>, where C names a concept, is the normal form of the constraint-expression of C, after substituting A, A, ..., A for C's respective template parameters in the parameter mappings in each atomic constraint.
    If any such substitution results in an invalid type or expression, the program is ill-formed; no diagnostic is required.
    [Example
    :
    template<typename T> concept A = T::value || true;
    template<typename U> concept B = A<U*>;
    template<typename V> concept C = B<V&>;
    
    Normalization of B's constraint-expression is valid and results in T::value (with the mapping T) true (with an empty mapping), despite the expression T::value being ill-formed for a pointer type T.
    Normalization of C's constraint-expression results in the program being ill-formed, because it would form the invalid type T&* in the parameter mapping.
    end example
    ]
  • The normal form of any other expression E is the atomic constraint whose expression is E and whose parameter mapping is the identity mapping.
The process of obtaining the normal form of a constraint-expression is called normalization.
[Note
:
Normalization of constraint-expressions is performed when determining the associated constraints ([temp.constr.constr]) of a declaration and when evaluating the value of an id-expression that names a concept specialization ([expr.prim.id]).
end note
]
[Example
:
template<typename T> concept C1 = sizeof(T) == 1;
template<typename T> concept C2 = C1<T>() && 1 == 2;
template<typename T> concept C3 = requires { typename T::type; };
template<typename T> concept C4 = requires (T x) { ++x; }

template<C2 U> void f1(U);      // #1
template<C3 U> void f2(U);      // #2
template<C4 U> void f3(U);      // #3
The associated constraints of #1 are sizeof(T) == 1 (with mapping TU) 1 == 2.

The associated constraints of #2 are requires { typename T::type; } (with mapping TU).

The associated constraints of #3 are requires (T x) { ++x; } (with mapping TU).
end example
]