191 lines
8.5 KiB
Markdown
191 lines
8.5 KiB
Markdown
[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<A1, A2, …, An> 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<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*](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<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); // #1template<C3 U> void f2(U); // #2template<C4 U> 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)*: template<typename T>concept C = true;template<typename T, template<typename> concept CT>concept CC = CT<T>;
|
||
|
||
template<typename U, template<typename, template<typename> concept> concept CT>void f() requires CT<U*, C>;template<typename U>void g() requires CC<U*, C>;
|
||
|
||
The normal form of the associated constraints of f is
|
||
the concept-dependent constraint CT<T, C>[.](#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)*: template<typename T>concept A = true;template<typename T>concept B = A<T> && true; // B subsumes Atemplate<typename T>concept C = true;template<typename T>concept D = C<T> && true; // D subsumes Ctemplate<typename T, template<typename> concept... CTs>concept all_of = (CTs<T> && ...);
|
||
|
||
template<typename T> requires all_of<T, A, C>constexpr int f(T) { return 1; } // #1template<typename T> 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<T> and C<T>[.](#3.sentence-6)
|
||
|
||
|
||
|
||
|
||
Similarly, the normal form of all_of<T, B, D> is
|
||
the conjunction of the normal forms of B<T> and D<T>[.](#3.sentence-7)
|
||
|
||
|
||
|
||
|
||
#2 therefore is more constrained than #1[.](#3.sentence-8)
|
||
|
||
â *end example*]
|
||
|
||
[*Example [5](#example-5)*: template<typename T, template<typename> concept>struct wrapper {};
|
||
|
||
template<typename... T, template<typename> concept... CTs>int f(wrapper<T, CTs>...) requires (CTs<T> && ...); // error: fold expression contains// different kinds of template parameters â *end example*]
|