Two expressions involving template parameters are considered
equivalent
if two function definitions containing the expressions would satisfy
the
one-definition rule, except that the tokens used
to name the template parameters may differ as long as a token used to
name a template parameter in one expression is replaced by another token
that names the same template parameter in the other expression
. Two unevaluated operands that do not involve template parameters
are considered equivalent
if two function definitions containing the expressions
would satisfy the one-definition rule,
except that the tokens used to name types and declarations may differ
as long as they name the same entities, and
the tokens used to form concept-ids (
[temp.names]) may differ
as long as the two
template-ids are the same (
[temp.type])
. [
Note 3:
For instance,
A<42> and
A<40+2> name the same type
. —
end note]
[
Note 4:
The intent is to avoid
lambda-expressions appearing in the
signature of a function template with external linkage
. —
end note]
For determining whether two dependent names (
[temp.dep]) are equivalent,
only the name itself is considered, not the result of name lookup
. [
Note 5:
If such a dependent name is unqualified,
it is looked up from
a first declaration of the function template (
[temp.res.general])
. —
end note]
[
Example 3:
template <int I, int J> void f(A<I+J>);
template <int K, int L> void f(A<K+L>);
template <class T> decltype(g(T())) h();
int g(int);
template <class T> decltype(g(T())) h()
{ return g(T()); }
int i = h<int>();
template <int N> void foo(const char (*s)[([]{}, N)]);
template <int N> void foo(const char (*s)[([]{}, N)]);
template <class T> void spam(decltype([]{}) (*s)[sizeof(T)]);
template <class T> void spam(decltype([]{}) (*s)[sizeof(T)]);
—
end example]
Two potentially-evaluated expressions involving template parameters that are not equivalent are
functionally equivalent
if, for any given set of template arguments, the evaluation of the
expression results in the same value
. Two unevaluated operands that are not equivalent
are functionally equivalent if, for any given set of template arguments,
the expressions perform
the same operations in the same order with the same entities
. [
Note 6:
For instance, one could have redundant parentheses
. —
end note]
[
Example 4:
template<int I> concept C = true;
template<typename T> struct A {
void f() requires C<42>;
void f() requires true;
};
—
end example]