[英]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;
}
这将编译但不会链接,因为friend
声明引入了一个从未定义过的非模板operator++
。
这个常见问题解答的内容如下(粗体是我的):
解决方案是在编译器检查 class 主体时说服编译器,
operator++
function 本身就是一个模板。 做这件事有很多种方法;
第一种方法是在朋友声明中加入<>
,这里不考虑。 第二个是“在class体内定义朋友function”:
template<class T> struct S {
friend void operator++(S) { }
};
引用表明void operator++(S)
现在是 function 模板,而不是非模板 function。 是吗?
它不是模板,因为它的声明不是模板的声明(即使它出现在模板声明本身中)。
[temp.friend] (强调我的)
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. 对于不是模板声明的朋友 function 声明:
如果朋友的名字是合格或不合格的模板ID,朋友声明指的是function模板的特化,否则,
如果朋友的名字是qualified-id并且在指定的class或命名空间中找到匹配的非模板function,则朋友声明指的是function,否则
如果朋友的名字是一个qualified-id并且匹配的function模板在指定的class或命名空间中找到,朋友声明是指推导出的那个ZC1C425268E68385D1AB5074C17A9模板的特化,否则[decFlZA4]
该名称应为声明(或重新声明)非模板 function 的非限定 ID 。
[ 例子:
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; };
这里,任务 class 模板的每个特化都有 function
next_time
作为好友; 因为process
没有明确的模板参数,任务 class 模板的每个特化都有一个适当类型的 functionprocess
作为朋友,而这个朋友不是 ZC1C425268E68385D1AB5074C17A94F 因为朋友preempt
有一个明确的模板参数T
,task
class 模板的每个特化都有 function 模板作为朋友preempt
的适当特化; 并且task
class 模板的每个特化具有func
模板的所有特化作为朋友。 类似地,task
class 模板的每个特化具有 class 模板特化task<int>
作为好友,并且具有 class 模板frd
的所有特化作为好友。 —结束示例]
虽然示例是非规范性的,但引文中的示例阐明了前述规范性文本的意图。 由于友元运算符声明不是模板声明,因此适用粗体文本。 因此它声明了一个非模板 function。
和
template<class T> struct S {
friend void operator++(S s) { }
};
operator ++
不再是模板。
对于更常规的 function ( 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});
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.