[ Note

: *end note*

]This subclause defines the meaning of constraints on template arguments.

The abstract syntax and satisfaction rules are defined
in [temp.constr.constr].

Constraints are associated with declarations in [temp.constr.decl].

Declarations are partially ordered by their associated constraints ([temp.constr.order]).

— A *constraint* is a sequence of logical operations and
operands that specifies requirements on template arguments.

The operands of a logical operation are constraints.

There are three different kinds of constraints:

In order for a constrained template to be instantiated ([temp.spec]),
its associated constraints
shall be satisfied as described in the following subclauses.

[ Note

: *end note*

]Forming the name of a specialization of
a class template,
a variable template, or
an alias template ([temp.names])
requires the satisfaction of its constraints.

Overload resolution
requires the satisfaction of constraints
on functions and function templates.

— There are two binary logical operations on constraints: conjunction
and disjunction.

A *conjunction* is a constraint taking two
operands.

If that is not satisfied, the conjunction is not satisfied.

Otherwise, the conjunction is satisfied if and only if the second
operand is satisfied.

A *disjunction* is a constraint taking two
operands.

If that is satisfied, the disjunction is satisfied.

Otherwise, the disjunction is satisfied if and only if the second
operand is satisfied.

[ Example

: *end example*

]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
of f, the constraint sizeof(char) > 1 is not satisfied;
the second operand is not checked for satisfaction.

— An *atomic constraint* is formed from
an expression E
and a mapping from the template parameters
that appear within E to
template arguments involving the
template parameters of the constrained entity,
called the *parameter mapping* ([temp.constr.decl]).

[ Note ]

Two atomic constraints are
*identical*
if they are formed from the same
*expression*
and the targets of the parameter mappings are equivalent
according to the rules for expressions described in [temp.over.link].

To determine if an atomic constraint is
*satisfied*,
the parameter mapping and template arguments are
first substituted into its expression.

If substitution results in an invalid type or expression,
the constraint is not satisfied.

Otherwise, the lvalue-to-rvalue conversion
is performed if necessary,
and E shall be a constant expression of type bool.

[ Example

: *end example*

]template<typename T> concept C = sizeof(T) == 4 && !true; // requires atomic constraints sizeof(T) == 4 and !true template<typename T> struct S { constexpr operator bool() const { return true; } }; template<typename T> requires (S<T>{}) void f(T); // #1 void f(int); // #2 void 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—

This allows the specification of constraints for that declaration as
an expression:

constraint-expression:logical-or-expression

Constraints can also be associated with a declaration through the use of
*type-constraint*s in a
*template-parameter-list*.

Each of these forms introduces additional *constraint-expression*s
that are used to constrain the declaration.

A template's *associated constraints* are defined as follows:

- Otherwise, if there is a single introduced
*constraint-expression*, the associated constraints are the normal form of that expression. - Otherwise, the associated constraints are the normal form of a logical AND expression whose operands are in the following order:
- the
*constraint-expression*introduced by each*type-constraint*([temp.param]) in the declaration's*template-parameter-list*, in order of appearance, and - the
*constraint-expression*introduced by a*requires-clause*following a*template-parameter-list*([temp]), and - the
*constraint-expression*introduced by each*type-constraint*in the parameter-type-list of a function declaration, and - the
*constraint-expression*introduced by a trailing*requires-clause*([dcl.decl]) of a function declaration ([dcl.fct]).

- the

The formation of the associated constraints
establishes the order in which constraints are instantiated when checking
for satisfaction ([temp.constr.constr]).

[ Example

: *end example*

]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>;

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);

template<C1 T> requires C2<T> void f6(); template<C2 T> requires C1<T> void f7();—

The *normal form* of an *expression* E is
a constraint that is defined as follows:

- The normal form of an expression ( E ) is the normal form of E.
- The normal form of an expression E1 || E2 is the disjunction of the normal forms of E1 and E2.
- The normal form of an expression E1 && E2 is the conjunction of the normal forms of E1 and E2.
- The normal form of an
*id-expression*of the form C<A, A, ..., A>, where C names a concept, is the normal form of the*constraint-expression*of C, after substituting A, A, ..., A for C's respective template parameters in the parameter mappings in each atomic constraint. If any such substitution results in an invalid type or expression, the program is ill-formed; no diagnostic is required.[ Example:]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*is valid and results in T::value (with the mapping ) ∨ true (with an empty mapping), despite the expression T::value being ill-formed for a pointer type T. Normalization of C's*constraint-expression*results in the program being ill-formed, because it would form the invalid type T&* in the parameter mapping. —*end example* - The normal form of any other expression E is the atomic constraint whose expression is E and whose parameter mapping is the identity mapping.

[ Note

: *end note*

]Normalization of *constraint-expression*s
is performed
when determining the associated constraints ([temp.constr.constr])
of a declaration
and
when evaluating the value of an *id-expression*
that names a concept specialization ([expr.prim.id]).

— [ Example

:

—*end example*

]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); // #1 template<C3 U> void f2(U); // #2 template<C4 U> void f3(U); // #3

—

A constraint P *subsumes* a constraint Q
if and only if,
for every disjunctive clause
in the disjunctive normal form132
of P, subsumes every conjunctive clause
in the conjunctive normal form133
of Q, where

- a disjunctive clause subsumes a conjunctive clause if and only if there exists an atomic constraint in for which there exists an atomic constraint in such that subsumes , and
- an atomic constraint A subsumes another atomic constraint B if and only if A and B are identical using the rules described in [temp.constr.atomic].

[ Note

: *end note*

]The subsumption relation defines a partial ordering on constraints.

This partial ordering is used to determine

— - the best viable candidate of non-template functions ([over.match.best]),
- the address of a non-template function ([over.over]),
- the matching of template template arguments,
- the partial ordering of class template specializations, and
- the partial ordering of function templates.

A declaration D1 is
*at least as constrained* as
a declaration D2 if

- D1 and D2 are both constrained declarations and D1's associated constraints subsume those of D2; or
- D2 has no associated constraints.

A declaration D1 is *more constrained*
than another declaration D2 when D1 is at least as
constrained as D2, and D2 is not at least as
constrained as D1.

[ Example

: *end example*

]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); // #1 template<C2 T> void f(T); // #2 template<typename T> void g(T); // #3 template<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—