Files
2025-10-25 03:02:53 +03:00

191 lines
8.5 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[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.4Constraint normalization[temp.constr.normal]") of an [*expression*](expr.comma#nt:expression "7.6.20Comma operator[expr.comma]") E is
a [constraint](temp.constr.constr#def:constraint "13.5.2Constraints[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.2Logical 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.3Constrained 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.3Constrained 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.3Constrained 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.7Fold expressions[expr.prim.fold]") Op ([[expr.prim.fold]](expr.prim.fold "7.5.7Fold 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.5Fold expanded constraint")) whose
constraint is E′ and whose [*fold-operator*](expr.prim.fold#nt:fold-operator "7.5.7Fold 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.3Constrained declarations[temp.constr.decl]") is called[*normalization*](#def:constraint,normalization "13.5.4Constraint normalization[temp.constr.normal]")[.](#2.sentence-1)
[*Note [1](#note-1)*:
Normalization of [*constraint-expression*](temp.constr.decl#nt:constraint-expression "13.5.3Constrained declarations[temp.constr.decl]")*s* is performed
when determining the associated constraints ([[temp.constr.constr]](temp.constr.constr "13.5.2Constraints"))
of a declaration
and
when evaluating the value of an [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1General[expr.prim.id.general]") that names a concept specialization ([[expr.prim.id]](expr.prim.id "7.5.5Names"))[.](#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*]