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 ) ∨ 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.

[ Note

: *end note*

]Normalization of *constraint-expression*s
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]).

— [ Example

:

—*end 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

—