[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 constexpr bool Atomic = true;template concept C = Atomic;template concept Add1 = C;template concept AddOne = C;template void f()requires Add1<2 * M>;template int f()requires AddOne<2 * M> && true; int x = f<0>(); // OK, the atomic constraints from concept C in both fs are Atomic// with mapping similar to N↦2 * M + 1template struct WrapN;template using Add1Ty = WrapN;template using AddOneTy = WrapN;template void g(Add1Ty<2 * M> *);template 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 void f2()requires Add1<2 * N>;template int f2()requires Add1 && 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 concept C =sizeof(T) == 4 && !true; // requires atomic constraints sizeof(T) == 4 and !truetemplate struct S {constexpr operator bool() const { return true; }}; template requires (S{})void f(T); // #1void f(int); // #2void g() { f(0); // error: expression S{} 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*]