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.

— [ Note

: *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-expressions
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

— : *end example*

]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

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]).

[ Note ]

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-parameters corresponding and equivalent ([temp.over.link]) to
those mapped by the parameter mappings of the expression,
a template-id naming A
whose template-arguments are
the targets of the parameter mapping of
is the same ([temp.type]) as
a template-id naming A
whose template-arguments are
the targets of the parameter mapping of .

[ Note

: *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

: *end example*

]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 }—

This similarity includes the situation where a program is ill-formed, no diagnostic required,
when the meaning of the program depends on whether two constructs are equivalent,
and they are functionally equivalent but not equivalent.

[ Example

— : *end example*

]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 }—

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.

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

: *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—