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-constraints
in a template-parameter-list or parameter-type-list.

Each of these forms introduces additional constraint-expressions
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 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, 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 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();—

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-expressions are not equivalent.

[Note

: *end note*

]This can happen when determining which member template is specialized
by an explicit specialization declaration.

— [Example

: *end example*

]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

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.

—