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

369 lines
20 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.constr]
# 13 Templates [[temp]](./#temp)
## 13.5 Template constraints [[temp.constr]](temp.constr#constr)
### 13.5.2 Constraints [temp.constr.constr]
#### [13.5.2.1](#general) General [[temp.constr.constr.general]](temp.constr.constr.general)
[1](#general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1610)
A [*constraint*](#def:constraint "13.5.2.1General[temp.constr.constr.general]") is a sequence of logical operations and
operands that specifies requirements on template arguments[.](#general-1.sentence-1)
The operands of a logical operation are constraints[.](#general-1.sentence-2)
There are five different kinds of constraints:
- [(1.1)](#general-1.1)
conjunctions ([[temp.constr.op]](#temp.constr.op "13.5.2.2Logical operations")),
- [(1.2)](#general-1.2)
disjunctions ([[temp.constr.op]](#temp.constr.op "13.5.2.2Logical operations")),
- [(1.3)](#general-1.3)
atomic constraints ([[temp.constr.atomic]](#temp.constr.atomic "13.5.2.3Atomic constraints")),
- [(1.4)](#general-1.4)
concept-dependent constraints ([[temp.constr.concept]](#temp.constr.concept "13.5.2.4Concept-dependent constraints")), and
- [(1.5)](#general-1.5)
fold expanded constraints ([[temp.constr.fold]](#temp.constr.fold "13.5.2.5Fold expanded constraint"))[.](#general-1.sentence-3)
[2](#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.9Template instantiation and specialization")),
its [associated constraints](temp.constr.decl#def:associated_constraints "13.5.3Constrained declarations[temp.constr.decl]") shall be satisfied as described in the following subclauses[.](#general-2.sentence-1)
[*Note [1](#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.3Names of template specializations"))
requires the satisfaction of its constraints[.](#general-2.sentence-2)
[Overload resolution](over.match.viable "12.2.3Viable functions[over.match.viable]") requires the satisfaction of constraints
on functions and function templates[.](#general-2.sentence-3)
— *end note*]
#### [13.5.2.2](#temp.constr.op) Logical operations [[temp.constr.op]](temp.constr.op)
[1](#temp.constr.op-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1640)
There are two binary logical operations on constraints: conjunction
and disjunction[.](#temp.constr.op-1.sentence-1)
[*Note [1](#temp.constr.op-note-1)*:
These logical operations have no corresponding C++ syntax[.](#temp.constr.op-1.sentence-2)
For the purpose of exposition, conjunction is spelled
using the symbol ∧ and disjunction is spelled using the
symbol ∨ [.](#temp.constr.op-1.sentence-3)
The operands of these operations are called the left
and right operands[.](#temp.constr.op-1.sentence-4)
In the constraint A ∧ B,A is the left operand, and B is the right operand[.](#temp.constr.op-1.sentence-5)
— *end note*]
[2](#temp.constr.op-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1653)
A [*conjunction*](#def:conjunction "13.5.2.2Logical operations[temp.constr.op]") is a constraint taking two
operands[.](#temp.constr.op-2.sentence-1)
To determine if a conjunction is[*satisfied*](#def:constraint,satisfaction,conjunction "13.5.2.2Logical operations[temp.constr.op]"),
the satisfaction of
the first operand is checked[.](#temp.constr.op-2.sentence-2)
If that is not satisfied, the conjunction is not satisfied[.](#temp.constr.op-2.sentence-3)
Otherwise, the conjunction is satisfied if and only if the second
operand is satisfied[.](#temp.constr.op-2.sentence-4)
[3](#temp.constr.op-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1664)
A [*disjunction*](#def:disjunction "13.5.2.2Logical operations[temp.constr.op]") is a constraint taking two
operands[.](#temp.constr.op-3.sentence-1)
To determine if a disjunction is[*satisfied*](#def:constraint,satisfaction,disjunction "13.5.2.2Logical operations[temp.constr.op]"),
the satisfaction of
the first operand is checked[.](#temp.constr.op-3.sentence-2)
If that is satisfied, the disjunction is satisfied[.](#temp.constr.op-3.sentence-3)
Otherwise, the disjunction is satisfied if and only if the second
operand is satisfied[.](#temp.constr.op-3.sentence-4)
[4](#temp.constr.op-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1676)
[*Example [1](#temp.constr.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](temp.constr.decl#def:associated_constraints "13.5.3Constrained declarations[temp.constr.decl]") of f, the constraint sizeof(char) > 1 is not satisfied;
the second operand is not checked for satisfaction[.](#temp.constr.op-4.sentence-1)
— *end example*]
[5](#temp.constr.op-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1695)
[*Note [2](#temp.constr.op-note-2)*:
A logical negation expression ([[expr.unary.op]](expr.unary.op "7.6.2.2Unary operators")) is an atomic constraint;
the negation operator is not treated as a logical operation on constraints[.](#temp.constr.op-5.sentence-1)
As a result, distinct negation [*constraint-expression*](temp.constr.decl#nt:constraint-expression "13.5.3Constrained declarations[temp.constr.decl]")*s* that are equivalent under [[temp.over.link]](temp.over.link "13.7.7.2Function template overloading") do not subsume one another under [[temp.constr.order]](temp.constr.order "13.5.5Partial ordering by constraints")[.](#temp.constr.op-5.sentence-2)
Furthermore, if substitution to determine
whether an atomic constraint is satisfied ([[temp.constr.atomic]](#temp.constr.atomic "13.5.2.3Atomic constraints"))
encounters a substitution failure, the constraint is not satisfied,
regardless of the presence of a negation operator[.](#temp.constr.op-5.sentence-3)
[*Example [2](#temp.constr.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]](#temp.constr.atomic "13.5.2.3Atomic constraints"))// are not formed from the same [*expression*](expr.comma#nt:expression "7.6.20Comma 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[.](#temp.constr.op-5.sentence-4)
— *end example*]
— *end note*]
#### [13.5.2.3](#temp.constr.atomic) Atomic constraints [[temp.constr.atomic]](temp.constr.atomic)
[1](#temp.constr.atomic-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1738)
An [*atomic constraint*](#def:constraint,atomic "13.5.2.3Atomic 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.3Atomic constraints[temp.constr.atomic]") ([[temp.constr.decl]](temp.constr.decl "13.5.3Constrained declarations"))[.](#temp.constr.atomic-1.sentence-1)
[*Note [1](#temp.constr.atomic-note-1)*:
Atomic constraints are formed by [constraint normalization](temp.constr.normal#def:constraint,normalization "13.5.4Constraint normalization[temp.constr.normal]")[.](#temp.constr.atomic-1.sentence-2)
E is never a [logical and expression](expr.log.and "7.6.14Logical AND operator[expr.log.and]") nor a [logical or expression](expr.log.or "7.6.15Logical OR operator[expr.log.or]")[.](#temp.constr.atomic-1.sentence-3)
— *end note*]
[2](#temp.constr.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.3Atomic constraints[temp.constr.atomic]") if they are formed from the same appearance of the same[*expression*](expr.comma#nt:expression "7.6.20Comma operator[expr.comma]") and if, given a hypothetical template A whose [*template-parameter-list*](temp.pre#nt:template-parameter-list "13.1Preamble[temp.pre]") consists of[*template-parameter*](temp.param#nt:template-parameter "13.2Template parameters[temp.param]")*s* corresponding and equivalent ([[temp.over.link]](temp.over.link "13.7.7.2Function template overloading")) to
those mapped by the parameter mappings of the expression,
a [*template-id*](temp.names#nt:template-id "13.3Names of template specializations[temp.names]") naming A whose [*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]")*s* are
the targets of the parameter mapping of e1 is the same ([[temp.type]](temp.type "13.6Type equivalence")) as
a [*template-id*](temp.names#nt:template-id "13.3Names of template specializations[temp.names]") naming A whose [*template-argument*](temp.names#nt:template-argument "13.3Names of template specializations[temp.names]")*s* are
the targets of the parameter mapping of e2[.](#temp.constr.atomic-2.sentence-1)
[*Note [2](#temp.constr.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.8Alias templates"))[.](#temp.constr.atomic-2.sentence-2)
[*Example [1](#temp.constr.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.2Function 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[.](#temp.constr.atomic-2.sentence-3)
[*Example [2](#temp.constr.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](#temp.constr.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.3Atomic constraints[temp.constr.atomic]"),
the parameter mapping and template arguments are
first substituted into its expression[.](#temp.constr.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.1General")),
the constraint is not satisfied[.](#temp.constr.atomic-3.sentence-2)
Otherwise, the [lvalue-to-rvalue conversion](conv.lval "7.3.2Lvalue-to-rvalue conversion[conv.lval]") is performed if necessary,
and E shall be a constant expression of type bool[.](#temp.constr.atomic-3.sentence-3)
The constraint is satisfied if and only if evaluation of E results in true[.](#temp.constr.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[.](#temp.constr.atomic-3.sentence-5)
[*Example [3](#temp.constr.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](#temp.constr.concept) Concept-dependent constraints [[temp.constr.concept]](temp.constr.concept)
[1](#temp.constr.concept-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1857)
A [*concept-dependent constraint*](#def:constraint,concept-dependent "13.5.2.4Concept-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.9Concept definitions[temp.concept]") names a dependent concept named C[.](#temp.constr.concept-1.sentence-1)
[2](#temp.constr.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.4Concept-dependent constraints[temp.constr.concept]"),
the parameter mapping and template arguments are first
substituted into C[.](#temp.constr.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.1General")),
the constraint is not satisfied[.](#temp.constr.concept-2.sentence-2)
Otherwise, let CI′ be
the normal form ([[temp.constr.normal]](temp.constr.normal "13.5.4Constraint normalization")) of the concept-id
after substitution of C[.](#temp.constr.concept-2.sentence-3)
[*Note [1](#temp.constr.concept-note-1)*:
Normalization of CI might be ill-formed; no diagnostics is required[.](#temp.constr.concept-2.sentence-4)
— *end note*]
[3](#temp.constr.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[.](#temp.constr.concept-3.sentence-1)
[4](#temp.constr.concept-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1886)
CD is satisfied if CI′′ is satisfied[.](#temp.constr.concept-4.sentence-1)
[*Note [2](#temp.constr.concept-note-2)*:
Checking whether CI′′ is satisfied
can lead to further normalization of concept-dependent constraints[.](#temp.constr.concept-4.sentence-2)
— *end note*]
[*Example [1](#temp.constr.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[.](#temp.constr.concept-4.sentence-3)
The result of substituting D into this expression is D<U, CT>[.](#temp.constr.concept-4.sentence-4)
We consider the normal form of the resulting concept-id,
which is CC<T> with the mappingT↦U,CC↦CT[.](#temp.constr.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[.](#temp.constr.concept-4.sentence-6)
— *end example*]
#### [13.5.2.5](#temp.constr.fold) Fold expanded constraint [[temp.constr.fold]](temp.constr.fold)
[1](#temp.constr.fold-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1920)
A [*fold expanded constraint*](#def:constraint,fold_expanded "13.5.2.5Fold expanded constraint[temp.constr.fold]") is formed from a constraint C and
a [*fold-operator*](expr.prim.fold#nt:fold-operator "7.5.7Fold expressions[expr.prim.fold]") which can either be && or ||[.](#temp.constr.fold-1.sentence-1)
A fold expanded constraint is a pack expansion ([[temp.variadic]](temp.variadic "13.7.4Variadic templates"))[.](#temp.constr.fold-1.sentence-2)
Let N be the number of elements
in the pack expansion parameters ([[temp.variadic]](temp.variadic "13.7.4Variadic templates"))[.](#temp.constr.fold-1.sentence-3)
[2](#temp.constr.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.7Fold 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[.](#temp.constr.fold-2.sentence-1)
No substitution takes place for any i greater than
the smallest i for which the constraint is not satisfied[.](#temp.constr.fold-2.sentence-2)
[3](#temp.constr.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.7Fold 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[.](#temp.constr.fold-3.sentence-1)
No substitution takes place for any i greater than
the smallest i for which the constraint is satisfied[.](#temp.constr.fold-3.sentence-2)
[4](#temp.constr.fold-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1948)
[*Note [1](#temp.constr.fold-note-1)*:
If the pack expansion expands packs of different size,
then it is invalid and the fold expanded constraint is not satisfied[.](#temp.constr.fold-4.sentence-1)
— *end note*]
[5](#temp.constr.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.5Fold expanded constraint[temp.constr.fold]") if their respective constraints both contain
an equivalent unexpanded pack ([[temp.over.link]](temp.over.link "13.7.7.2Function template overloading"))[.](#temp.constr.fold-5.sentence-1)