[temp.constr.normal] # 13 Templates [[temp]](./#temp) ## 13.5 Template constraints [[temp.constr]](temp.constr#normal) ### 13.5.4 Constraint normalization [temp.constr.normal] [1](#1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2085) The [*normal form*](#def:normal_form,constraint "13.5.4 Constraint normalization [temp.constr.normal]") of an [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") E is a [constraint](temp.constr.constr#def:constraint "13.5.2 Constraints [temp.constr.constr]") that is defined as follows: - [(1.1)](#1.1) The normal form of an expression ( E ) is the normal form of E[.](#1.1.sentence-1) - [(1.2)](#1.2) The normal form of an expression E1 || E2 is the [disjunction](temp.constr.op#def:disjunction "13.5.2.2 Logical operations [temp.constr.op]") of the normal forms of E1 and E2[.](#1.2.sentence-1) - [(1.3)](#1.3) The normal form of an expression E1 && E2 is the conjunction of the normal forms of E1 and E2[.](#1.3.sentence-1) - [(1.4)](#1.4) For a concept-id C termed CI: * [(1.4.1)](#1.4.1) 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[.](#1.4.1.sentence-1) * [(1.4.2)](#1.4.2) Otherwise, to form CE, any non-dependent concept template argument Ai is substituted into the [*constraint-expression*](temp.constr.decl#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]") of C[.](#1.4.2.sentence-1) If any such substitution results in an invalid concept-id, the program is ill-formed; no diagnostic is required[.](#1.4.2.sentence-2) 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[.](#1.4.2.sentence-3) If any such substitution results in an invalid type or expression, the program is ill-formed; no diagnostic is required[.](#1.4.2.sentence-4) [*Example [1](#example-1)*: template concept A = T::value || true;template concept B = A;template concept C = B; Normalization of B's [*constraint-expression*](temp.constr.decl#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]") 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[.](#1.4.sentence-2) Normalization of C's [*constraint-expression*](temp.constr.decl#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]") results in the program being ill-formed, because it would form the invalid type V&* in the parameter mapping[.](#1.4.sentence-3) — *end example*] - [(1.5)](#1.5) For a [*fold-operator*](expr.prim.fold#nt:fold-operator "7.5.7 Fold expressions [expr.prim.fold]") Op ([[expr.prim.fold]](expr.prim.fold "7.5.7 Fold expressions")) that is either && or ||: * [(1.5.1)](#1.5.1) The normal form of an expression ( ... Op E ) is the normal form of ( E Op ... )[.](#1.5.1.sentence-1) * [(1.5.2)](#1.5.2) The normal form of an expression ( E1 Op ... Op E2 ) is the normal form of + [(1.5.2.1)](#1.5.2.1) ( E1 Op ... ) Op E2 if E1 contains an unexpanded pack, or + [(1.5.2.2)](#1.5.2.2) E1 Op ( E2 Op ... ) otherwise[.](#1.5.2.sentence-1) * [(1.5.3)](#1.5.3) 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[.](#1.5.3.sentence-2) Let E′ be the normal form of E[.](#1.5.3.sentence-3) + [(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[.](#1.5.3.1.sentence-1) 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[.](#1.5.3.1.sentence-2) If any such substitution results in an invalid type or expression, the program is ill-formed; no diagnostic is required[.](#1.5.3.1.sentence-3) + [(1.5.3.2)](#1.5.3.2) Otherwise, the normal form of F is a fold expanded constraint ([[temp.constr.fold]](temp.constr.fold "13.5.2.5 Fold expanded constraint")) whose constraint is E′ and whose [*fold-operator*](expr.prim.fold#nt:fold-operator "7.5.7 Fold expressions [expr.prim.fold]") is Op[.](#1.5.3.2.sentence-1) - [(1.6)](#1.6) The normal form of any other expression E is the atomic constraint whose expression is E and whose parameter mapping is the identity mapping[.](#1.6.sentence-1) [2](#2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2201) The process of obtaining the normal form of a[*constraint-expression*](temp.constr.decl#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]") is called[*normalization*](#def:constraint,normalization "13.5.4 Constraint normalization [temp.constr.normal]")[.](#2.sentence-1) [*Note [1](#note-1)*: Normalization of [*constraint-expression*](temp.constr.decl#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]")*s* is performed when determining the associated constraints ([[temp.constr.constr]](temp.constr.constr "13.5.2 Constraints")) of a declaration and when evaluating the value of an [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") that names a concept specialization ([[expr.prim.id]](expr.prim.id "7.5.5 Names"))[.](#2.sentence-2) — *end note*] [3](#3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2217) [*Example [2](#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[.](#3.sentence-1) The associated constraints of #2 arerequires { typename T​::​type; } (with mapping T↦U)[.](#3.sentence-2) The associated constraints of #3 arerequires (T x) { ++x; } (with mapping T↦U)[.](#3.sentence-3) — *end example*] [*Example [3](#example-3)*: templateconcept C = true;template concept CT>concept CC = CT; template concept> concept CT>void f() requires CT;templatevoid g() requires CC; The normal form of the associated constraints of f is the concept-dependent constraint CT[.](#3.sentence-4) The normal form of the associated constraints of g is the atomic constraint true[.](#3.sentence-5) — *end example*] [*Example [4](#example-4)*: templateconcept A = true;templateconcept B = A && true; // B subsumes Atemplateconcept C = true;templateconcept D = C && true; // D subsumes Ctemplate concept... CTs>concept all_of = (CTs && ...); template requires all_ofconstexpr int f(T) { return 1; } // #1template requires all_ofconstexpr int f(T) { return 2; } // #2static_assert(f(1) == 2); // ok The normal form of all_of is the conjunction of the normal forms of A and C[.](#3.sentence-6) Similarly, the normal form of all_of is the conjunction of the normal forms of B and D[.](#3.sentence-7) #2 therefore is more constrained than #1[.](#3.sentence-8) — *end example*] [*Example [5](#example-5)*: template concept>struct wrapper {}; template concept... CTs>int f(wrapper...) requires (CTs && ...); // error: fold expression contains// different kinds of template parameters — *end example*]