88 lines
6.1 KiB
Markdown
88 lines
6.1 KiB
Markdown
[temp.constr.atomic]
|
||
|
||
# 13 Templates [[temp]](./#temp)
|
||
|
||
## 13.5 Template constraints [[temp.constr]](temp.constr#atomic)
|
||
|
||
### 13.5.2 Constraints [[temp.constr.constr]](temp.constr.constr#temp.constr.atomic)
|
||
|
||
#### 13.5.2.3 Atomic constraints [temp.constr.atomic]
|
||
|
||
[1](#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]](temp.constr.decl "13.5.3 Constrained declarations"))[.](#1.sentence-1)
|
||
|
||
[*Note [1](#note-1)*:
|
||
|
||
Atomic constraints are formed by [constraint normalization](temp.constr.normal#def:constraint,normalization "13.5.4 Constraint normalization [temp.constr.normal]")[.](#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]")[.](#1.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[2](#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[.](#2.sentence-1)
|
||
|
||
[*Note [2](#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"))[.](#2.sentence-2)
|
||
|
||
[*Example [1](#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[.](#2.sentence-3)
|
||
|
||
[*Example [2](#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](#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[.](#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[.](#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[.](#3.sentence-3)
|
||
|
||
The constraint is satisfied if and only if evaluation of E results in true[.](#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[.](#3.sentence-5)
|
||
|
||
[*Example [3](#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*]
|