Suppose we have the following code:
template<class T> struct S;
template<class T> void operator++(S<T>);
template<class T> struct S {
friend void operator++(S);
};
template<class T>
void operator++(S<T>) {}
int main() {
S<int> s;
++s;
}
This will compile but won't link, because the friend
declaration introduces a non-template operator++
, that has never been defined.
This FAQ answer reads (bold is mine):
The solution is to convince the compiler while it is examining the class body proper that the
operator++
function is itself a template. There are several ways to do this;
The first way is to add <>
into the friend declaration, and I'm not considering it here. The second is "to define the friend function within the class body":
template<class T> struct S {
friend void operator++(S) { }
};
The quote suggests that void operator++(S)
is now a function template and not a non-template function. Is it?
It is not a template, because its declaration is not that of a template (even though it appears inside a template declaration itself).
[temp.friend] (emphasis mine)
1 A friend of a class or class template can be a function template or class template, a specialization of a function template or class template, or a non-template function or class. For a friend function declaration that is not a template declaration:
if the name of the friend is a qualified or unqualified template-id, the friend declaration refers to a specialization of a function template, otherwise,
if the name of the friend is a qualified-id and a matching non-template function is found in the specified class or namespace, the friend declaration refers to that function, otherwise,
if the name of the friend is a qualified-id and a matching function template is found in the specified class or namespace, the friend declaration refers to the deduced specialization of that function template ([temp.deduct.decl]), otherwise,
the name shall be an unqualified-id that declares (or redeclares) a non-template function.
[ Example:
template<class T> class task; template<class T> task<T>* preempt(task<T>*); template<class T> class task { friend void next_time(); friend void process(task<T>*); friend task<T>* preempt<T>(task<T>*); template<class C> friend int func(C); friend class task<int>; template<class P> friend class frd; };
Here, each specialization of the task class template has the function
next_time
as a friend; becauseprocess
does not have explicit template-arguments, each specialization of the task class template has an appropriately typed functionprocess
as a friend, and this friend is not a function template specialization; because the friendpreempt
has an explicit template-argumentT
, each specialization of thetask
class template has the appropriate specialization of the function templatepreempt
as a friend; and each specialization of thetask
class template has all specializations of the function templatefunc
as friends. Similarly, each specialization of thetask
class template has the class template specializationtask<int>
as a friend, and has all specializations of the class templatefrd
as friends. — end example ]
While examples are non-normative, the one in the quote clarifies the intent of the preceding normative text. Since the friend operator declaration is not a template declaration, the text in bold applies. It therefore declares a non-template function.