具有定义的友元函数 - 模板还是非模板?
Friend function with a definition - template or non-template?
假设我们有以下代码:
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;
}
这会编译但不会 link,因为 friend
声明引入了一个从未定义过的非模板 operator++
。
This FAQ answer 阅读(粗体 是我的):
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;
第一种方式是在好友声明中加入<>
,这里不考虑。第二个是 "to define the friend function within the class body":
template<class T> struct S {
friend void operator++(S) { }
};
引用表明 void operator++(S)
现在是函数模板而不是非模板函数。是吗?
有
template<class T> struct S {
friend void operator++(S s) { }
};
operator ++
不再是模板。
对于更常规的功能(operator
用法与功能略有不同),它可能允许推导:
template<class T> struct S {
S(T t);
friend void foo(S lhs, S rhs) { }
};
template <typename T>
void bar(S<T> s, T t)
{
foo(s, t); // would not work if foo was template, would require foo<T>(s, t);
foo(s, {t}); // would not work if foo was template, would require foo<T>(s, {t});
}
它不是模板,因为它的声明不是模板的声明(即使它出现在模板声明本身内部)。
[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; because process
does not have explicit
template-arguments, each specialization of the task class template has
an appropriately typed function process
as a friend, and this friend
is not a function template specialization; because the friend
preempt
has an explicit template-argument T
, each specialization
of the task
class template has the appropriate specialization of the
function template preempt
as a friend; and each specialization of
the task
class template has all specializations of the function
template func
as friends. Similarly, each specialization of the
task
class template has the class template specialization
task<int>
as a friend, and has all specializations of the class
template frd
as friends. — end example ]
虽然示例是非规范性的,但引用中的示例阐明了前面规范性文本的意图。由于友元运算符声明不是模板声明,因此适用粗体文本。因此它声明了一个非模板函数。
假设我们有以下代码:
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;
}
这会编译但不会 link,因为 friend
声明引入了一个从未定义过的非模板 operator++
。
This FAQ answer 阅读(粗体 是我的):
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;
第一种方式是在好友声明中加入<>
,这里不考虑。第二个是 "to define the friend function within the class body":
template<class T> struct S {
friend void operator++(S) { }
};
引用表明 void operator++(S)
现在是函数模板而不是非模板函数。是吗?
有
template<class T> struct S {
friend void operator++(S s) { }
};
operator ++
不再是模板。
对于更常规的功能(operator
用法与功能略有不同),它可能允许推导:
template<class T> struct S {
S(T t);
friend void foo(S lhs, S rhs) { }
};
template <typename T>
void bar(S<T> s, T t)
{
foo(s, t); // would not work if foo was template, would require foo<T>(s, t);
foo(s, {t}); // would not work if foo was template, would require foo<T>(s, {t});
}
它不是模板,因为它的声明不是模板的声明(即使它出现在模板声明本身内部)。
[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 ]
虽然示例是非规范性的,但引用中的示例阐明了前面规范性文本的意图。由于友元运算符声明不是模板声明,因此适用粗体文本。因此它声明了一个非模板函数。