[*Note 1*: *end note*]

Subclause [temp.constr] 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 four different kinds of constraints:

- conjunctions ([temp.constr.op]),
- disjunctions ([temp.constr.op]),
- atomic constraints ([temp.constr.atomic]), and
- fold expanded constraints ([temp.constr.fold]).

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

[*Note 1*: *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.

[*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)
*end example*]

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.

— [*Note 2*: — *end note*]

A logical negation expression ([expr.unary.op]) is an atomic constraint;
the negation operator is not treated as a logical operation on constraints.

As a result, distinct negation *constraint-expression**s*
that are equivalent under [temp.over.link]
do not subsume one another under [temp.constr.order].

Furthermore, if substitution to determine
whether an atomic constraint is satisfied ([temp.constr.atomic])
encounters a substitution failure, the constraint is not satisfied,
regardless of the presence of a negation operator.

[*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])
// are not formed from the same *expression*
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_sad
template <class T> int f3(T) requires (!sad<typename T::type>);
int i3 = f3(42); // error: associated constraints not satisfied due to substitution failure
template <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
*end example*]

Here,
requires (!sad<typename T::type>) requires
that there is a nested type that is not sad,
whereas
requires (!sad_nested_type<T>) requires
that there is no sad nested type.

— An *atomic constraint* 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* ([temp.constr.decl]).

Two atomic constraints, and , are
*identical*
if they are formed from the same appearance of the same
*expression*
and if, given a hypothetical template A
whose *template-parameter-list* consists of
*template-parameter**s* corresponding and equivalent ([temp.over.link]) to
those mapped by the parameter mappings of the expression,
a *template-id* naming A
whose *template-argument**s* are
the targets of the parameter mapping of
is the same ([temp.type]) as
a *template-id* naming A
whose *template-argument**s* are
the targets of the parameter mapping of .

[*Note 2*: — *end note*]

The comparison of parameter mappings of atomic constraints
operates in a manner similar to that of declaration matching
with alias template substitution ([temp.alias]).

[*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
template <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],
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.

[*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*]

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
in the immediate context of the atomic constraint ([temp.deduct.general]),
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.

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.

[*Example 3*: 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
— *end example*]

A *fold expanded constraint* is formed from a constraint C and
a *fold-operator*
which can either be && or ||.

A fold expanded constraint is a pack expansion ([temp.variadic]).

A fold expanded constraint whose *fold-operator* is &&
is satisfied if it is a valid pack expansion and
if or if for each i where in increasing order,
C is satisfied
when replacing each pack expansion parameter
with the corresponding element.

No substitution takes place for any i greater than
the smallest i for which the constraint is not satisfied.

A fold expanded constraint whose *fold-operator* is ||
is satisfied if it is a valid pack expansion,
, and if for i where in increasing order,
there is a smallest i for which C is satisfied
when replacing each pack expansion parameter
with the corresponding element.

No substitution takes place for any i greater than
the smallest i for which the constraint is satisfied.

Two fold expanded constraints are *compatible for subsumption*
if their respective constraints both contain
an equivalent unexpanded pack ([temp.over.link]).

A template declaration ([temp.pre])
or templated function declaration ([dcl.fct])
can be constrained by the use of a *requires-clause*.

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

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

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

A declaration'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.pre]), 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 1*: 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();
— *end example*]

When determining whether a given introduced
*constraint-expression* of a declaration
in an instantiated specialization of a templated class
is equivalent ([temp.over.link]) to the corresponding
*constraint-expression* of a declaration
outside the class body,
is instantiated.

If the instantiation results in an invalid expression,
the *constraint-expression**s* are not equivalent.

[*Example 2*: template <class T> concept C = true;
template <class T> struct A {
template <class U> U f(U) requires C<typename T::type>; // #1
template <class U> U f(U) requires C<T>; // #2
};
template <> template <class U>
U A<int>::f(U u) requires C<int> { return u; } // OK, specializes #2
*end example*]

Substituting int for T in C<typename T::type>
produces an invalid expression, so the specialization does not match #1.

Substituting int for T in C<T> produces C<int>,
which is equivalent to the *constraint-expression* for the specialization,
so it does match #2.

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

- The normal form of a concept-id C<A, A, ..., A> 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 1*: 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 V&* in the parameter mapping.*end example*] - For a
*fold-operator*([expr.prim.fold]) that is either && or ||, the normal form of an expression ( ...*fold-operator*E ) is the normal form of ( E*fold-operator*... ). - For a
*fold-operator*that is either && or ||, the normal form of an expression ( E1*fold-operator*...*fold-operator*E2 ) is the normal form of- ( E1
*fold-operator*... )*fold-operator*E2 if E1 contains an unexpanded pack, or - E1
*fold-operator*( E2*fold-operator*... ) otherwise.

- ( E1
- The normal form of ( E && ... ) is a fold expanded constraint ([temp.constr.fold]) whose constraint is the normal form of E and whose
*fold-operator*is &&. - The normal form of ( E || ... ) is a fold expanded constraint whose constraint is the normal form of E and whose
*fold-operator*is ||. - 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 1*: *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 2*: 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

—*end example*]

—

A constraint P *subsumes* a constraint Q
if and only if,
for every disjunctive clause
in the disjunctive normal form113
of P, subsumes every conjunctive clause
in the conjunctive normal form114
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 ,
- 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], and
- a fold expanded constraint A subsumes
another fold expanded constraint B
if they are compatible for subsumption,
have the same
*fold-operator*, and the constraint of A subsumes that of B.

[*Note 1*: *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 ([temp.arg.template]),
- the partial ordering of class template specializations ([temp.spec.partial.order]), and
- the partial ordering of function templates ([temp.func.order]).

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 2*: 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
— *end example*]