849 lines
43 KiB
Markdown
849 lines
43 KiB
Markdown
[temp.constr]
|
||
|
||
# 13 Templates [[temp]](./#temp)
|
||
|
||
## 13.5 Template constraints [temp.constr]
|
||
|
||
### [13.5.1](#general) General [[temp.constr.general]](temp.constr.general)
|
||
|
||
[1](#general-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1595)
|
||
|
||
[*Note [1](#general-note-1)*:
|
||
|
||
Subclause [temp.constr] defines the meaning of constraints on template arguments[.](#general-1.sentence-1)
|
||
|
||
The abstract syntax and satisfaction rules are defined
|
||
in [[temp.constr.constr]](#constr "13.5.2 Constraints")[.](#general-1.sentence-2)
|
||
|
||
Constraints are associated with declarations in [[temp.constr.decl]](#decl "13.5.3 Constrained declarations")[.](#general-1.sentence-3)
|
||
|
||
Declarations are partially ordered by their associated constraints ([[temp.constr.order]](#order "13.5.5 Partial ordering by constraints"))[.](#general-1.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
### [13.5.2](#constr) Constraints [[temp.constr.constr]](temp.constr.constr)
|
||
|
||
#### [13.5.2.1](#constr.general) General [[temp.constr.constr.general]](temp.constr.constr.general)
|
||
|
||
[1](#constr.general-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1610)
|
||
|
||
A [*constraint*](#def:constraint "13.5.2.1 General [temp.constr.constr.general]") is a sequence of logical operations and
|
||
operands that specifies requirements on template arguments[.](#constr.general-1.sentence-1)
|
||
|
||
The operands of a logical operation are constraints[.](#constr.general-1.sentence-2)
|
||
|
||
There are five different kinds of constraints:
|
||
|
||
- [(1.1)](#constr.general-1.1)
|
||
|
||
conjunctions ([[temp.constr.op]](#op "13.5.2.2 Logical operations")),
|
||
|
||
- [(1.2)](#constr.general-1.2)
|
||
|
||
disjunctions ([[temp.constr.op]](#op "13.5.2.2 Logical operations")),
|
||
|
||
- [(1.3)](#constr.general-1.3)
|
||
|
||
atomic constraints ([[temp.constr.atomic]](#atomic "13.5.2.3 Atomic constraints")),
|
||
|
||
- [(1.4)](#constr.general-1.4)
|
||
|
||
concept-dependent constraints ([[temp.constr.concept]](#concept "13.5.2.4 Concept-dependent constraints")), and
|
||
|
||
- [(1.5)](#constr.general-1.5)
|
||
|
||
fold expanded constraints ([[temp.constr.fold]](#fold "13.5.2.5 Fold expanded constraint"))[.](#constr.general-1.sentence-3)
|
||
|
||
[2](#constr.general-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1623)
|
||
|
||
In order for a constrained template to be instantiated ([[temp.spec]](temp.spec "13.9 Template instantiation and specialization")),
|
||
its [associated constraints](#def:associated_constraints "13.5.3 Constrained declarations [temp.constr.decl]") shall be satisfied as described in the following subclauses[.](#constr.general-2.sentence-1)
|
||
|
||
[*Note [1](#constr.general-note-1)*:
|
||
|
||
Forming the name of a specialization of
|
||
a class template,
|
||
a variable template, or
|
||
an alias template ([[temp.names]](temp.names "13.3 Names of template specializations"))
|
||
requires the satisfaction of its constraints[.](#constr.general-2.sentence-2)
|
||
|
||
[Overload resolution](over.match.viable "12.2.3 Viable functions [over.match.viable]") requires the satisfaction of constraints
|
||
on functions and function templates[.](#constr.general-2.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
#### [13.5.2.2](#op) Logical operations [[temp.constr.op]](temp.constr.op)
|
||
|
||
[1](#op-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1640)
|
||
|
||
There are two binary logical operations on constraints: conjunction
|
||
and disjunction[.](#op-1.sentence-1)
|
||
|
||
[*Note [1](#op-note-1)*:
|
||
|
||
These logical operations have no corresponding C++ syntax[.](#op-1.sentence-2)
|
||
|
||
For the purpose of exposition, conjunction is spelled
|
||
using the symbol â§ and disjunction is spelled using the
|
||
symbol ⨠[.](#op-1.sentence-3)
|
||
|
||
The operands of these operations are called the left
|
||
and right operands[.](#op-1.sentence-4)
|
||
|
||
In the constraint A â§ B,A is the left operand, and B is the right operand[.](#op-1.sentence-5)
|
||
|
||
â *end note*]
|
||
|
||
[2](#op-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1653)
|
||
|
||
A [*conjunction*](#def:conjunction "13.5.2.2 Logical operations [temp.constr.op]") is a constraint taking two
|
||
operands[.](#op-2.sentence-1)
|
||
|
||
To determine if a conjunction is[*satisfied*](#def:constraint,satisfaction,conjunction "13.5.2.2 Logical operations [temp.constr.op]"),
|
||
the satisfaction of
|
||
the first operand is checked[.](#op-2.sentence-2)
|
||
|
||
If that is not satisfied, the conjunction is not satisfied[.](#op-2.sentence-3)
|
||
|
||
Otherwise, the conjunction is satisfied if and only if the second
|
||
operand is satisfied[.](#op-2.sentence-4)
|
||
|
||
[3](#op-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1664)
|
||
|
||
A [*disjunction*](#def:disjunction "13.5.2.2 Logical operations [temp.constr.op]") is a constraint taking two
|
||
operands[.](#op-3.sentence-1)
|
||
|
||
To determine if a disjunction is[*satisfied*](#def:constraint,satisfaction,disjunction "13.5.2.2 Logical operations [temp.constr.op]"),
|
||
the satisfaction of
|
||
the first operand is checked[.](#op-3.sentence-2)
|
||
|
||
If that is satisfied, the disjunction is satisfied[.](#op-3.sentence-3)
|
||
|
||
Otherwise, the disjunction is satisfied if and only if the second
|
||
operand is satisfied[.](#op-3.sentence-4)
|
||
|
||
[4](#op-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1676)
|
||
|
||
[*Example [1](#op-example-1)*: template<typename T>constexpr bool get_value() { return T::value; }template<typename T>requires (sizeof(T) > 1) && (get_value<T>())void f(T); // has associated constraint sizeof(T) > 1 â§ get_value<T>()void f(int);
|
||
|
||
f('a'); // OK, calls f(int)
|
||
|
||
In the satisfaction of the [associated constraints](#def:associated_constraints "13.5.3 Constrained declarations [temp.constr.decl]") of f, the constraint sizeof(char) > 1 is not satisfied;
|
||
the second operand is not checked for satisfaction[.](#op-4.sentence-1)
|
||
|
||
â *end example*]
|
||
|
||
[5](#op-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1695)
|
||
|
||
[*Note [2](#op-note-2)*:
|
||
|
||
A logical negation expression ([[expr.unary.op]](expr.unary.op "7.6.2.2 Unary operators")) is an atomic constraint;
|
||
the negation operator is not treated as a logical operation on constraints[.](#op-5.sentence-1)
|
||
|
||
As a result, distinct negation [*constraint-expression*](#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]")*s* that are equivalent under [[temp.over.link]](temp.over.link "13.7.7.2 Function template overloading") do not subsume one another under [[temp.constr.order]](#order "13.5.5 Partial ordering by constraints")[.](#op-5.sentence-2)
|
||
|
||
Furthermore, if substitution to determine
|
||
whether an atomic constraint is satisfied ([[temp.constr.atomic]](#atomic "13.5.2.3 Atomic constraints"))
|
||
encounters a substitution failure, the constraint is not satisfied,
|
||
regardless of the presence of a negation operator[.](#op-5.sentence-3)
|
||
|
||
[*Example [2](#op-example-2)*: template <class T> concept sad = false;
|
||
|
||
template <class T> int f1(T) requires (!sad<T>);template <class T> int f1(T) requires (!sad<T>) && true;int i1 = f1(42); // ambiguous, !sad<T> atomic constraint expressions ([[temp.constr.atomic]](#atomic "13.5.2.3 Atomic constraints"))// are not formed from the same [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]")template <class T> concept not_sad = !sad<T>;template <class T> int f2(T) requires not_sad<T>;template <class T> int f2(T) requires not_sad<T> && true;int i2 = f2(42); // OK, !sad<T> atomic constraint expressions both come from not_sadtemplate <class T> int f3(T) requires (!sad<typename T::type>);int i3 = f3(42); // error: associated constraints not satisfied due to substitution failuretemplate <class T> concept sad_nested_type = sad<typename T::type>;template <class T> int f4(T) requires (!sad_nested_type<T>);int i4 = f4(42); // OK, substitution failure contained within sad_nested_type
|
||
|
||
Here,requires (!sad<typename T::type>) requires
|
||
that there is a nested type that is not sad,
|
||
whereasrequires (!sad_nested_type<T>) requires
|
||
that there is no sad nested type[.](#op-5.sentence-4)
|
||
|
||
â *end example*]
|
||
|
||
â *end note*]
|
||
|
||
#### [13.5.2.3](#atomic) Atomic constraints [[temp.constr.atomic]](temp.constr.atomic)
|
||
|
||
[1](#atomic-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1738)
|
||
|
||
An [*atomic constraint*](#def:constraint,atomic "13.5.2.3 Atomic constraints [temp.constr.atomic]") is formed from
|
||
an expression E and a mapping from the template parameters
|
||
that appear within E to
|
||
template arguments that are formed via substitution during constraint normalization
|
||
in the declaration of a constrained entity (and, therefore, can involve the
|
||
unsubstituted template parameters of the constrained entity),
|
||
called the [*parameter mapping*](#def:parameter_mapping "13.5.2.3 Atomic constraints [temp.constr.atomic]") ([[temp.constr.decl]](#decl "13.5.3 Constrained declarations"))[.](#atomic-1.sentence-1)
|
||
|
||
[*Note [1](#atomic-note-1)*:
|
||
|
||
Atomic constraints are formed by [constraint normalization](#def:constraint,normalization "13.5.4 Constraint normalization [temp.constr.normal]")[.](#atomic-1.sentence-2)
|
||
|
||
E is never a [logical and expression](expr.log.and "7.6.14 Logical AND operator [expr.log.and]") nor a [logical or expression](expr.log.or "7.6.15 Logical OR operator [expr.log.or]")[.](#atomic-1.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[2](#atomic-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1753)
|
||
|
||
Two atomic constraints, e1 and e2, are[*identical*](#def:atomic_constraint,identical "13.5.2.3 Atomic constraints [temp.constr.atomic]") if they are formed from the same appearance of the same[*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") and if, given a hypothetical template A whose [*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1 Preamble [temp.pre]") consists of[*template-parameter*](temp.param#nt:template-parameter "13.2 Template parameters [temp.param]")*s* corresponding and equivalent ([[temp.over.link]](temp.over.link "13.7.7.2 Function template overloading")) to
|
||
those mapped by the parameter mappings of the expression,
|
||
a [*template-id*](temp.names#nt:template-id "13.3 Names of template specializations [temp.names]") naming A whose [*template-argument*](temp.names#nt:template-argument "13.3 Names of template specializations [temp.names]")*s* are
|
||
the targets of the parameter mapping of e1 is the same ([[temp.type]](temp.type "13.6 Type equivalence")) as
|
||
a [*template-id*](temp.names#nt:template-id "13.3 Names of template specializations [temp.names]") naming A whose [*template-argument*](temp.names#nt:template-argument "13.3 Names of template specializations [temp.names]")*s* are
|
||
the targets of the parameter mapping of e2[.](#atomic-2.sentence-1)
|
||
|
||
[*Note [2](#atomic-note-2)*:
|
||
|
||
The comparison of parameter mappings of atomic constraints
|
||
operates in a manner similar to that of declaration matching
|
||
with alias template substitution ([[temp.alias]](temp.alias "13.7.8 Alias templates"))[.](#atomic-2.sentence-2)
|
||
|
||
[*Example [1](#atomic-example-1)*: template <unsigned N> constexpr bool Atomic = true;template <unsigned N> concept C = Atomic<N>;template <unsigned N> concept Add1 = C<N + 1>;template <unsigned N> concept AddOne = C<N + 1>;template <unsigned M> void f()requires Add1<2 * M>;template <unsigned M> int f()requires AddOne<2 * M> && true;
|
||
|
||
int x = f<0>(); // OK, the atomic constraints from concept C in both fs are Atomic<N>// with mapping similar to Nâ¦2 * M + 1template <unsigned N> struct WrapN;template <unsigned N> using Add1Ty = WrapN<N + 1>;template <unsigned N> using AddOneTy = WrapN<N + 1>;template <unsigned M> void g(Add1Ty<2 * M> *);template <unsigned M> void g(AddOneTy<2 * M> *);
|
||
|
||
void h() { g<0>(nullptr); // OK, there is only one g} â *end example*]
|
||
|
||
As specified in [[temp.over.link]](temp.over.link "13.7.7.2 Function template overloading"),
|
||
if the validity or meaning of the program depends on
|
||
whether two constructs are equivalent, and
|
||
they are functionally equivalent but not equivalent,
|
||
the program is ill-formed, no diagnostic required[.](#atomic-2.sentence-3)
|
||
|
||
[*Example [2](#atomic-example-2)*: template <unsigned N> void f2()requires Add1<2 * N>;template <unsigned N> int f2()requires Add1<N * 2> && true;void h2() { f2<0>(); // ill-formed, no diagnostic required:// requires determination of subsumption between atomic constraints that are// functionally equivalent but not equivalent} â *end example*]
|
||
|
||
â *end note*]
|
||
|
||
[3](#atomic-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1819)
|
||
|
||
To determine if an atomic constraint is[*satisfied*](#def:constraint,satisfaction,atomic "13.5.2.3 Atomic constraints [temp.constr.atomic]"),
|
||
the parameter mapping and template arguments are
|
||
first substituted into its expression[.](#atomic-3.sentence-1)
|
||
|
||
If substitution results in an invalid type or expression
|
||
in the immediate context of the atomic constraint ([[temp.deduct.general]](temp.deduct.general "13.10.3.1 General")),
|
||
the constraint is not satisfied[.](#atomic-3.sentence-2)
|
||
|
||
Otherwise, the [lvalue-to-rvalue conversion](conv.lval "7.3.2 Lvalue-to-rvalue conversion [conv.lval]") is performed if necessary,
|
||
and E shall be a constant expression of type bool[.](#atomic-3.sentence-3)
|
||
|
||
The constraint is satisfied if and only if evaluation of E results in true[.](#atomic-3.sentence-4)
|
||
|
||
If, at different points in the program, the satisfaction result is different
|
||
for identical atomic constraints and template arguments,
|
||
the program is ill-formed, no diagnostic required[.](#atomic-3.sentence-5)
|
||
|
||
[*Example [3](#atomic-example-3)*: template<typename T> concept C =sizeof(T) == 4 && !true; // requires atomic constraints sizeof(T) == 4 and !truetemplate<typename T> struct S {constexpr operator bool() const { return true; }};
|
||
|
||
template<typename T> requires (S<T>{})void f(T); // #1void f(int); // #2void g() { f(0); // error: expression S<int>{} does not have type bool} // while checking satisfaction of deduced arguments of #1;// call is ill-formed even though #2 is a better match â *end example*]
|
||
|
||
#### [13.5.2.4](#concept) Concept-dependent constraints [[temp.constr.concept]](temp.constr.concept)
|
||
|
||
[1](#concept-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1857)
|
||
|
||
A [*concept-dependent constraint*](#def:constraint,concept-dependent "13.5.2.4 Concept-dependent constraints [temp.constr.concept]") CD is
|
||
an atomic constraint whose expression is a concept-id CI whose[*concept-name*](temp.concept#nt:concept-name "13.7.9 Concept definitions [temp.concept]") names a dependent concept named C[.](#concept-1.sentence-1)
|
||
|
||
[2](#concept-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1862)
|
||
|
||
To determine if CD is[*satisfied*](#def:constraint,satisfaction,concept-dependent "13.5.2.4 Concept-dependent constraints [temp.constr.concept]"),
|
||
the parameter mapping and template arguments are first
|
||
substituted into C[.](#concept-2.sentence-1)
|
||
|
||
If substitution results in an invalid concept-id in
|
||
the immediate context of the constraint ([[temp.deduct.general]](temp.deduct.general "13.10.3.1 General")),
|
||
the constraint is not satisfied[.](#concept-2.sentence-2)
|
||
|
||
Otherwise, let CIâ² be
|
||
the normal form ([[temp.constr.normal]](#normal "13.5.4 Constraint normalization")) of the concept-id
|
||
after substitution of C[.](#concept-2.sentence-3)
|
||
|
||
[*Note [1](#concept-note-1)*:
|
||
|
||
Normalization of CI might be ill-formed; no diagnostics is required[.](#concept-2.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
[3](#concept-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1877)
|
||
|
||
To form CIâ²â²,
|
||
each appearance of C's template parameters in
|
||
the parameter mappings of the atomic constraints
|
||
(including concept-dependent constraints)
|
||
in CIâ² is substituted with their respective arguments from
|
||
the parameter mapping of CD and the arguments of CI[.](#concept-3.sentence-1)
|
||
|
||
[4](#concept-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1886)
|
||
|
||
CD is satisfied if CIâ²â² is satisfied[.](#concept-4.sentence-1)
|
||
|
||
[*Note [2](#concept-note-2)*:
|
||
|
||
Checking whether CIâ²â² is satisfied
|
||
can lead to further normalization of concept-dependent constraints[.](#concept-4.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[*Example [1](#concept-example-1)*: template<typename>concept C = true;
|
||
|
||
template<typename T, template<typename> concept CC>concept D = CC<T>;
|
||
|
||
template<typename U, template<typename> concept CT, template<typename, template<typename> concept> concept CU>int f() requires CU<U, CT>;int i = f<int, C, D>();
|
||
|
||
In this example, the associated constraints of f consist of a concept-dependent constraint
|
||
whose expression is the concept-id CU<U, CT> with the mappingUâ¦U,CTâ¦CT,CUâ¦CU[.](#concept-4.sentence-3)
|
||
|
||
The result of substituting D into this expression is D<U, CT>[.](#concept-4.sentence-4)
|
||
|
||
We consider the normal form of the resulting concept-id,
|
||
which is CC<T> with the mappingTâ¦U,CCâ¦CT[.](#concept-4.sentence-5)
|
||
|
||
By recursion, C is substituted into CC<T>, and the result
|
||
is normalized to the atomic constraint true, which is satisfied[.](#concept-4.sentence-6)
|
||
|
||
â *end example*]
|
||
|
||
#### [13.5.2.5](#fold) Fold expanded constraint [[temp.constr.fold]](temp.constr.fold)
|
||
|
||
[1](#fold-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1920)
|
||
|
||
A [*fold expanded constraint*](#def:constraint,fold_expanded "13.5.2.5 Fold expanded constraint [temp.constr.fold]") is formed from a constraint C and
|
||
a [*fold-operator*](expr.prim.fold#nt:fold-operator "7.5.7 Fold expressions [expr.prim.fold]") which can either be && or ||[.](#fold-1.sentence-1)
|
||
|
||
A fold expanded constraint is a pack expansion ([[temp.variadic]](temp.variadic "13.7.4 Variadic templates"))[.](#fold-1.sentence-2)
|
||
|
||
Let N be the number of elements
|
||
in the pack expansion parameters ([[temp.variadic]](temp.variadic "13.7.4 Variadic templates"))[.](#fold-1.sentence-3)
|
||
|
||
[2](#fold-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1928)
|
||
|
||
A fold expanded constraint whose [*fold-operator*](expr.prim.fold#nt:fold-operator "7.5.7 Fold expressions [expr.prim.fold]") is && is satisfied if it is a valid pack expansion and
|
||
if N=0 or if for each i where 0â¤i<N in increasing order,C is satisfied
|
||
when replacing each pack expansion parameter
|
||
with the corresponding ith element[.](#fold-2.sentence-1)
|
||
|
||
No substitution takes place for any i greater than
|
||
the smallest i for which the constraint is not satisfied[.](#fold-2.sentence-2)
|
||
|
||
[3](#fold-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1938)
|
||
|
||
A fold expanded constraint whose [*fold-operator*](expr.prim.fold#nt:fold-operator "7.5.7 Fold expressions [expr.prim.fold]") is || is satisfied if it is a valid pack expansion,N>0, and if for i where 0â¤i<N in increasing order,
|
||
there is a smallest i for which C is satisfied
|
||
when replacing each pack expansion parameter
|
||
with the corresponding ith element[.](#fold-3.sentence-1)
|
||
|
||
No substitution takes place for any i greater than
|
||
the smallest i for which the constraint is satisfied[.](#fold-3.sentence-2)
|
||
|
||
[4](#fold-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1948)
|
||
|
||
[*Note [1](#fold-note-1)*:
|
||
|
||
If the pack expansion expands packs of different size,
|
||
then it is invalid and the fold expanded constraint is not satisfied[.](#fold-4.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
[5](#fold-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1954)
|
||
|
||
Two fold expanded constraints are [*compatible for subsumption*](#def:subsumption,compatible_for "13.5.2.5 Fold expanded constraint [temp.constr.fold]") if their respective constraints both contain
|
||
an equivalent unexpanded pack ([[temp.over.link]](temp.over.link "13.7.7.2 Function template overloading"))[.](#fold-5.sentence-1)
|
||
|
||
### [13.5.3](#decl) Constrained declarations [[temp.constr.decl]](temp.constr.decl)
|
||
|
||
[1](#decl-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1961)
|
||
|
||
A template declaration ([[temp.pre]](temp.pre "13.1 Preamble"))
|
||
or templated function declaration ([[dcl.fct]](dcl.fct "9.3.4.6 Functions"))
|
||
can be constrained by the use of a [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]")[.](#decl-1.sentence-1)
|
||
|
||
This allows the specification of constraints for that declaration as
|
||
an expression:
|
||
|
||
[constraint-expression:](#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]")
|
||
[*logical-or-expression*](expr.log.or#nt:logical-or-expression "7.6.15 Logical OR operator [expr.log.or]")
|
||
|
||
[2](#decl-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1972)
|
||
|
||
Constraints can also be associated with a declaration through the use of[*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]")*s* in a [*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1 Preamble [temp.pre]") or parameter-type-list[.](#decl-2.sentence-1)
|
||
|
||
Each of these forms introduces additional [*constraint-expression*](#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]")*s* that are used to constrain the declaration[.](#decl-2.sentence-2)
|
||
|
||
[3](#decl-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1979)
|
||
|
||
A declaration's [*associated constraints*](#def:associated_constraints "13.5.3 Constrained declarations [temp.constr.decl]") are defined as follows:
|
||
|
||
- [(3.1)](#decl-3.1)
|
||
|
||
If there are no introduced [*constraint-expression*](#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]")*s*,
|
||
the declaration has no associated constraints[.](#decl-3.1.sentence-1)
|
||
|
||
- [(3.2)](#decl-3.2)
|
||
|
||
Otherwise, if there is a single introduced [*constraint-expression*](#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]"),
|
||
the associated constraints are the [normal form](#def:normal_form,constraint "13.5.4 Constraint normalization [temp.constr.normal]") of that expression[.](#decl-3.2.sentence-1)
|
||
|
||
- [(3.3)](#decl-3.3)
|
||
|
||
Otherwise, the associated constraints are the normal form of a [logicaland expression](expr.log.and "7.6.14 Logical AND operator [expr.log.and]") whose operands are in the
|
||
following order:
|
||
* [(3.3.1)](#decl-3.3.1)
|
||
|
||
the [*constraint-expression*](#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]") introduced by
|
||
each [*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]") ([[temp.param]](temp.param "13.2 Template parameters")) in
|
||
the declaration's [*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1 Preamble [temp.pre]"),
|
||
in order of appearance, and
|
||
|
||
* [(3.3.2)](#decl-3.3.2)
|
||
|
||
the [*constraint-expression*](#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]") introduced by
|
||
a [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") following
|
||
a [*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1 Preamble [temp.pre]") ([[temp.pre]](temp.pre "13.1 Preamble")), and
|
||
|
||
* [(3.3.3)](#decl-3.3.3)
|
||
|
||
the [*constraint-expression*](#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]") introduced by
|
||
each [*type-constraint*](temp.param#nt:type-constraint "13.2 Template parameters [temp.param]") in
|
||
the parameter-type-list of a function declaration, and
|
||
|
||
* [(3.3.4)](#decl-3.3.4)
|
||
|
||
the [*constraint-expression*](#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]") introduced by
|
||
a trailing [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") ([[dcl.decl]](dcl.decl "9.3 Declarators")) of
|
||
a function declaration ([[dcl.fct]](dcl.fct "9.3.4.6 Functions"))[.](#decl-3.3.sentence-1)
|
||
|
||
The formation of the associated constraints
|
||
establishes the order in which constraints are instantiated when checking
|
||
for satisfaction ([[temp.constr.constr]](#constr "13.5.2 Constraints"))[.](#decl-3.sentence-2)
|
||
|
||
[*Example [1](#decl-example-1)*: template<typename T> concept C = true;
|
||
|
||
template<C T> void f1(T);template<typename T> requires C<T> void f2(T);template<typename T> void f3(T) requires C<T>;
|
||
|
||
The functions f1, f2, and f3 have the associated
|
||
constraint C<T>[.](#decl-3.sentence-3)
|
||
|
||
template<typename T> concept C1 = true;template<typename T> concept C2 = sizeof(T) > 0;
|
||
|
||
template<C1 T> void f4(T) requires C2<T>;template<typename T> requires C1<T> && C2<T> void f5(T);
|
||
|
||
The associated constraints of f4 and f5 are C1<T> â§ C2<T>[.](#decl-3.sentence-4)
|
||
|
||
template<C1 T> requires C2<T> void f6();template<C2 T> requires C1<T> void f7();
|
||
|
||
The associated constraints off6 are C1<T> â§ C2<T>,
|
||
and those off7 are C2<T> â§ C1<T>[.](#decl-3.sentence-5)
|
||
|
||
â *end example*]
|
||
|
||
[4](#decl-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2051)
|
||
|
||
When determining whether a given introduced[*constraint-expression*](#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]") C1 of a declaration
|
||
in an instantiated specialization of a templated class
|
||
is equivalent ([[temp.over.link]](temp.over.link "13.7.7.2 Function template overloading")) to the corresponding[*constraint-expression*](#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]") C2 of a declaration
|
||
outside the class body,C1 is instantiated[.](#decl-4.sentence-1)
|
||
|
||
If the instantiation results in an invalid expression,
|
||
the [*constraint-expression*](#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]")*s* are not equivalent[.](#decl-4.sentence-2)
|
||
|
||
[*Note [1](#decl-note-1)*:
|
||
|
||
This can happen when determining which member template is specialized
|
||
by an explicit specialization declaration[.](#decl-4.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[*Example [2](#decl-example-2)*: template <class T> concept C = true;template <class T> struct A {template <class U> U f(U) requires C<typename T::type>; // #1template <class U> U f(U) requires C<T>; // #2};
|
||
|
||
template <> template <class U> U A<int>::f(U u) requires C<int> { return u; } // OK, specializes #2
|
||
|
||
Substituting int for T in C<typename T::type> produces an invalid expression, so the specialization does not match #1[.](#decl-4.sentence-4)
|
||
|
||
Substituting int for T in C<T> produces C<int>,
|
||
which is equivalent to the [*constraint-expression*](#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]") for the specialization,
|
||
so it does match #2[.](#decl-4.sentence-5)
|
||
|
||
â *end example*]
|
||
|
||
### [13.5.4](#normal) Constraint normalization [[temp.constr.normal]](temp.constr.normal)
|
||
|
||
[1](#normal-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](#def:constraint "13.5.2 Constraints [temp.constr.constr]") that is defined as follows:
|
||
|
||
- [(1.1)](#normal-1.1)
|
||
|
||
The normal form of an expression ( E ) is
|
||
the normal form of E[.](#normal-1.1.sentence-1)
|
||
|
||
- [(1.2)](#normal-1.2)
|
||
|
||
The normal form of an expression E1 || E2 is
|
||
the [disjunction](#def:disjunction "13.5.2.2 Logical operations [temp.constr.op]") of
|
||
the normal forms of E1 and E2[.](#normal-1.2.sentence-1)
|
||
|
||
- [(1.3)](#normal-1.3)
|
||
|
||
The normal form of an expression E1 && E2 is the conjunction of
|
||
the normal forms of E1 and E2[.](#normal-1.3.sentence-1)
|
||
|
||
- [(1.4)](#normal-1.4)
|
||
|
||
For a concept-id C<A1, A2, …, An> termed CI:
|
||
* [(1.4.1)](#normal-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[.](#normal-1.4.1.sentence-1)
|
||
|
||
* [(1.4.2)](#normal-1.4.2)
|
||
|
||
Otherwise, to form CE,
|
||
any non-dependent concept template argument Ai is substituted into the [*constraint-expression*](#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]") of C[.](#normal-1.4.2.sentence-1)
|
||
If any such substitution results in an invalid concept-id,
|
||
the program is ill-formed; no diagnostic is required[.](#normal-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[.](#normal-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[.](#normal-1.4.2.sentence-4)
|
||
|
||
[*Example [1](#normal-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*](#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[.](#normal-1.4.sentence-2)
|
||
Normalization of C's [*constraint-expression*](#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[.](#normal-1.4.sentence-3)
|
||
â *end example*]
|
||
|
||
- [(1.5)](#normal-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)](#normal-1.5.1)
|
||
|
||
The normal form of an expression ( ... Op E ) is the normal form of ( E Op ... )[.](#normal-1.5.1.sentence-1)
|
||
|
||
* [(1.5.2)](#normal-1.5.2)
|
||
|
||
The normal form of an expression ( E1 Op ... Op E2 ) is the normal form of
|
||
+
|
||
[(1.5.2.1)](#normal-1.5.2.1)
|
||
( E1 Op ... ) Op E2 if E1 contains an unexpanded pack, or
|
||
|
||
+
|
||
[(1.5.2.2)](#normal-1.5.2.2)
|
||
E1 Op ( E2 Op ... ) otherwise[.](#normal-1.5.2.sentence-1)
|
||
|
||
* [(1.5.3)](#normal-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[.](#normal-1.5.3.sentence-2)
|
||
Let Eâ² be the normal form of E[.](#normal-1.5.3.sentence-3)
|
||
|
||
+
|
||
[(1.5.3.1)](#normal-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[.](#normal-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[.](#normal-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[.](#normal-1.5.3.1.sentence-3)
|
||
|
||
+
|
||
[(1.5.3.2)](#normal-1.5.3.2)
|
||
Otherwise,
|
||
the normal form of F is
|
||
a fold expanded constraint ([[temp.constr.fold]](#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[.](#normal-1.5.3.2.sentence-1)
|
||
|
||
- [(1.6)](#normal-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[.](#normal-1.6.sentence-1)
|
||
|
||
[2](#normal-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2201)
|
||
|
||
The process of obtaining the normal form of a[*constraint-expression*](#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]")[.](#normal-2.sentence-1)
|
||
|
||
[*Note [1](#normal-note-1)*:
|
||
|
||
Normalization of [*constraint-expression*](#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]")*s* is performed
|
||
when determining the associated constraints ([[temp.constr.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"))[.](#normal-2.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[3](#normal-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2217)
|
||
|
||
[*Example [2](#normal-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[.](#normal-3.sentence-1)
|
||
|
||
|
||
|
||
|
||
The associated constraints of #2 arerequires { typename T::type; } (with mapping Tâ¦U)[.](#normal-3.sentence-2)
|
||
|
||
|
||
|
||
|
||
The associated constraints of #3 arerequires (T x) { ++x; } (with mapping Tâ¦U)[.](#normal-3.sentence-3)
|
||
|
||
â *end example*]
|
||
|
||
[*Example [3](#normal-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>[.](#normal-3.sentence-4)
|
||
|
||
|
||
|
||
|
||
The normal form of the associated constraints of g is
|
||
the atomic constraint true[.](#normal-3.sentence-5)
|
||
|
||
â *end example*]
|
||
|
||
[*Example [4](#normal-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>[.](#normal-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>[.](#normal-3.sentence-7)
|
||
|
||
|
||
|
||
|
||
#2 therefore is more constrained than #1[.](#normal-3.sentence-8)
|
||
|
||
â *end example*]
|
||
|
||
[*Example [5](#normal-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*]
|
||
|
||
### [13.5.5](#order) Partial ordering by constraints [[temp.constr.order]](temp.constr.order)
|
||
|
||
[1](#order-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2299)
|
||
|
||
A constraint P [*subsumes*](#def:constraint,subsumption "13.5.5 Partial ordering by constraints [temp.constr.order]") a constraint Q if and only if,
|
||
for every disjunctive clause Pi in the disjunctive normal form[110](#footnote-110 "A constraint is in disjunctive normal form when it is a disjunction of clauses where each clause is a conjunction of fold expanded or atomic constraints. For atomic constraints A, B, and C, the disjunctive normal form of the constraint A ⧠(B ⨠C) is (A ⧠B) ⨠(A ⧠C). Its disjunctive clauses are (A ⧠B) and (A ⧠C).") of P, Pi subsumes every conjunctive clause Qj in the conjunctive normal form[111](#footnote-111 "A constraint is in conjunctive normal form when it is a conjunction of clauses where each clause is a disjunction of fold expanded or atomic constraints. For atomic constraints A, B, and C, the constraint A ⧠(B ⨠C) is in conjunctive normal form. Its conjunctive clauses are A and (B ⨠C).") of Q, where
|
||
|
||
- [(1.1)](#order-1.1)
|
||
|
||
a disjunctive clause Pi subsumes a conjunctive clause Qj if and only
|
||
if there exists an atomic constraint Pia in Pi for which there exists
|
||
an atomic constraint Qjb in Qj such that Pia subsumes Qjb,
|
||
|
||
- [(1.2)](#order-1.2)
|
||
|
||
an atomic constraint A subsumes another atomic constraintB if and only if A and B are identical using the
|
||
rules described in [[temp.constr.atomic]](#atomic "13.5.2.3 Atomic constraints"), and
|
||
|
||
- [(1.3)](#order-1.3)
|
||
|
||
a fold expanded constraint A subsumes
|
||
another fold expanded constraint B if they are compatible for subsumption,
|
||
have the same [*fold-operator*](expr.prim.fold#nt:fold-operator "7.5.7 Fold expressions [expr.prim.fold]"), and
|
||
the constraint of A subsumes that of B[.](#order-1.sentence-1)
|
||
|
||
[*Example [1](#order-example-1)*:
|
||
|
||
Let A and B be [atomic constraints](#def:constraint,atomic "13.5.2.3 Atomic constraints [temp.constr.atomic]")[.](#order-1.sentence-2)
|
||
|
||
The constraint A â§ B subsumes A, but A does not subsume A â§ B[.](#order-1.sentence-3)
|
||
|
||
The constraint A subsumes A ⨠B, but A ⨠B does not subsume A[.](#order-1.sentence-4)
|
||
|
||
Also note that every constraint subsumes itself[.](#order-1.sentence-5)
|
||
|
||
â *end example*]
|
||
|
||
[2](#order-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2354)
|
||
|
||
[*Note [1](#order-note-1)*:
|
||
|
||
The subsumption relation defines a partial ordering on constraints[.](#order-2.sentence-1)
|
||
|
||
This partial ordering is used to determine
|
||
|
||
- [(2.1)](#order-2.1)
|
||
|
||
the best viable candidate of non-template functions ([[over.match.best]](over.match.best "12.2.4 Best viable function")),
|
||
|
||
- [(2.2)](#order-2.2)
|
||
|
||
the address of a non-template function ([[over.over]](over.over "12.3 Address of an overload set")),
|
||
|
||
- [(2.3)](#order-2.3)
|
||
|
||
the matching of template template arguments ([[temp.arg.template]](temp.arg.template "13.4.4 Template template arguments")),
|
||
|
||
- [(2.4)](#order-2.4)
|
||
|
||
the partial ordering of class template specializations ([[temp.spec.partial.order]](temp.spec.partial.order "13.7.6.3 Partial ordering of partial specializations")), and
|
||
|
||
- [(2.5)](#order-2.5)
|
||
|
||
the partial ordering of function templates ([[temp.func.order]](temp.func.order "13.7.7.3 Partial ordering of function templates"))[.](#order-2.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[3](#order-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2367)
|
||
|
||
The associated constraints C of a declaration Dare [*eligible for subsumption*](#def:eligible,for_subsumption "13.5.5 Partial ordering by constraints [temp.constr.order]") unless C contains a concept-dependent constraint[.](#order-3.sentence-1)
|
||
|
||
[4](#order-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2378)
|
||
|
||
A declaration D1 is[*at least as constrained*](#def:at_least_as_constrained "13.5.5 Partial ordering by constraints [temp.constr.order]") as
|
||
a declaration D2 if
|
||
|
||
- [(4.1)](#order-4.1)
|
||
|
||
D1 and D2 are both constrained declarations andD1's associated constraints
|
||
are eligible for subsumption and subsume those of D2; or
|
||
|
||
- [(4.2)](#order-4.2)
|
||
|
||
D2 has no associated constraints[.](#order-4.sentence-1)
|
||
|
||
[5](#order-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2390)
|
||
|
||
A declaration D1 is [*more constrained*](#def:more_constrained "13.5.5 Partial ordering by constraints [temp.constr.order]") than another declaration D2 when D1 is at least as
|
||
constrained as D2, and D2 is not at least as
|
||
constrained as D1[.](#order-5.sentence-1)
|
||
|
||
[*Example [2](#order-example-2)*: template<typename T> concept C1 = requires(T t) { --t; };template<typename T> concept C2 = C1<T> && requires(T t) { *t; };
|
||
|
||
template<C1 T> void f(T); // #1template<C2 T> void f(T); // #2template<typename T> void g(T); // #3template<C1 T> void g(T); // #4 f(0); // selects #1 f((int*)0); // selects #2 g(true); // selects #3 because C1<bool> is not satisfied g(0); // selects #4 â *end example*]
|
||
|
||
[*Example [3](#order-example-3)*: template<template<typename T> concept CT, typename T>struct S {};template<typename T>concept A = true;
|
||
|
||
template<template<typename T> concept X, typename T>int f(S<X, T>) requires A<T> { return 42; } // #1template<template<typename T> concept X, typename T>int f(S<X, T>) requires X<T> { return 43; } // #2 f(S<A, int>{}); // ok, select #1 because #2 is not eligible for subsumption â *end example*]
|
||
|
||
[6](#order-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L2427)
|
||
|
||
A non-template function F1 is [*more partial-ordering-constrained*](#def:more_partial-ordering-constrained "13.5.5 Partial ordering by constraints [temp.constr.order]") than a non-template function F2 if
|
||
|
||
- [(6.1)](#order-6.1)
|
||
|
||
they have the same non-object-parameter-type-lists ([[dcl.fct]](dcl.fct "9.3.4.6 Functions")), and
|
||
|
||
- [(6.2)](#order-6.2)
|
||
|
||
if they are member functions, both are direct members of the same class, and
|
||
|
||
- [(6.3)](#order-6.3)
|
||
|
||
if both are non-static member functions,
|
||
they have the same types for their object parameters, and
|
||
|
||
- [(6.4)](#order-6.4)
|
||
|
||
the declaration of F1 is more constrained than
|
||
the declaration of F2[.](#order-6.sentence-1)
|
||
|
||
[110)](#footnote-110)[110)](#footnoteref-110)
|
||
|
||
A constraint is in disjunctive normal form when it is a disjunction of
|
||
clauses where each clause is a conjunction of fold expanded or atomic constraints[.](#footnote-110.sentence-1)
|
||
|
||
For atomic constraints A, B, and C, the disjunctive normal form
|
||
of the constraintA ⧠(B ⨠C) is(A ⧠B) ⨠(A ⧠C)[.](#footnote-110.sentence-2)
|
||
|
||
Its disjunctive clauses are (A â§ B) and (A â§ C)[.](#footnote-110.sentence-3)
|
||
|
||
[111)](#footnote-111)[111)](#footnoteref-111)
|
||
|
||
A constraint is in conjunctive normal form when it is a conjunction
|
||
of clauses where each clause is a disjunction of fold expanded or atomic constraints[.](#footnote-111.sentence-1)
|
||
|
||
For atomic constraints A, B, and C, the constraintA ⧠(B ⨠C) is in conjunctive normal form[.](#footnote-111.sentence-2)
|
||
|
||
Its conjunctive clauses are A and (B ⨠C)[.](#footnote-111.sentence-3)
|