8.5 KiB
[temp.constr.normal]
13 Templates [temp]
13.5 Template constraints [temp.constr]
13.5.4 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.
-
For a concept-id C<A1, A2, …, An> termed CI:
-
If C names a dependent concept, the normal form of CI is a concept-dependent constraint whose concept-id is CI and whose parameter mapping is the identity mapping.
-
Otherwise, to form CE, any non-dependent concept template argument Ai is substituted into the constraint-expression of C. If any such substitution results in an invalid concept-id, the program is ill-formed; no diagnostic is required. The normal form of CI is the result of substituting, in the normal form N of CE, appearances of C's template parameters in the parameter mappings of the atomic constraints in N with their respective arguments from C. If any such substitution results in an invalid type or expression, the program is ill-formed; no diagnostic is required.
[Example 1: template concept A = T::value || true;template concept B = A<U*>;template concept C = B<V&>; Normalization of B's constraint-expression is valid and results inT::value (with the mapping Tâ¦U*) ⨠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 V&* in the parameter mapping. â end example]
-
-
For a fold-operator Op ([expr.prim.fold]) that is either && or ||:
E1 Op ( E2 Op ... ) otherwise.
-
The normal form of an expression F of the form ( E Op ... ) is as follows:
If E contains an unexpanded concept template parameter pack, it shall not contain an unexpanded template parameter pack of another kind. Let Eâ² be the normal form of E.-
[(1.5.3.1)](#1.5.3.1) If E contains
-
an unexpanded concept template parameter pack Pk that has corresponding template arguments in the parameter mapping of any atomic constraint (including concept-dependent constraints) of Eâ², the number of arguments specified for all such Pk shall be the same number N. The normal form of F is the normal form of E0 Op Op ENâ1 after substituting in Ei the respective ith concept argument of each Pk. If any such substitution results in an invalid type or expression, the program is ill-formed; no diagnostic is required.
+
[(1.5.3.2)](#1.5.3.2)
Otherwise,
the normal form of F is a fold expanded constraint ([temp.constr.fold]) whose constraint is Eâ² and whose fold-operator is Op.
-
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 aconstraint-expression is callednormalization.
[Note 1:
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 2: template concept C1 = sizeof(T) == 1;template concept C2 = C1 && 1 == 2;template concept C3 = requires { typename T::type; };template concept C4 = requires (T x) { ++x; };
template void f1(U); // #1template void f2(U); // #2template void f3(U); // #3
The associated constraints of #1 aresizeof(T) == 1 (with mapping Tâ¦U) â§ 1 == 2.
The associated constraints of #2 arerequires { typename T::type; } (with mapping Tâ¦U).
The associated constraints of #3 arerequires (T x) { ++x; } (with mapping Tâ¦U).
â end example]
[Example 3: templateconcept C = true;template<typename T, template concept CT>concept CC = CT;
template<typename U, template<typename, template concept> concept CT>void f() requires CT<U*, C>;templatevoid g() requires CC<U*, C>;
The normal form of the associated constraints of f is the concept-dependent constraint CT<T, C>.
The normal form of the associated constraints of g is the atomic constraint true.
â end example]
[Example 4: templateconcept A = true;templateconcept B = A && true; // B subsumes Atemplateconcept C = true;templateconcept D = C && true; // D subsumes Ctemplate<typename T, template concept... CTs>concept all_of = (CTs && ...);
template requires all_of<T, A, C>constexpr int f(T) { return 1; } // #1template requires all_of<T, B, D>constexpr int f(T) { return 2; } // #2static_assert(f(1) == 2); // ok
The normal form of all_of<T, A, C> is the conjunction of the normal forms of A and C.
Similarly, the normal form of all_of<T, B, D> is the conjunction of the normal forms of B and D.
#2 therefore is more constrained than #1.
â end example]
[Example 5: template<typename T, template concept>struct wrapper {};
template<typename... T, template concept... CTs>int f(wrapper<T, CTs>...) requires (CTs && ...); // error: fold expression contains// different kinds of template parameters â end example]