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

88 lines
6.1 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.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.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"))[.](#1.sentence-1)
[*Note [1](#note-1)*:
Atomic constraints are formed by [constraint normalization](temp.constr.normal#def:constraint,normalization "13.5.4Constraint normalization[temp.constr.normal]")[.](#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]")[.](#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.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[.](#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.8Alias 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.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[.](#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.3Atomic 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.1General")),
the constraint is not satisfied[.](#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[.](#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*]