给定以下代码。
#include <iostream>
template<typename T>
class Foo
{
public:
Foo(const T& value = T());
friend Foo<T> operator+ (const Foo<T>& lhs, const Foo<T>& rhs)
{
// ...
}
friend std::ostream& operator<< (std::ostream& o, const Foo<T>& x)
{
// ...
}
private:
T value_;
};
编译器可以毫无问题地编译两个具有模板参数的友元函数,而无需使用以下语法
template <typename T>
friend Foo<T> operator+ (const Foo<T>& lhs, const Foo<T>& rhs)
或
friend Foo<T> operator+ <>(const Foo<T>& lhs, const Foo<T>& rhs)
或
friend Foo<T> operator+ <T>(const Foo<T>& lhs, const Foo<T>& rhs)
因为它们已由模板类本身的实现定义。
编译器如何在不包含模板声明的情况下使用模板参数编译这些友元函数?为什么只在类中实现它们就足够了?
我从 here 了解到这个概念在“为什么我使用模板 friend 时会出现链接器错误?”部分下
最佳答案
这两个选项,带和不带 template<class T>
, 做一些稍微不同的事情。
当你介绍一个 friend
以这种方式运行,您可以通过 ADL(参数相关查找)才能访问的方式在封闭的命名空间中引入它。
template<class T>
引入函数模板,不引入函数模板的引入实际函数。
所以这样:
template<class T>
struct foo {
friend void bar(foo<T>){}
};
表示当foo<int>
存在,函数 bar(foo<int>)
被 build 。然后 foo<double>
创建bar(foo<double>)
.
这些中的每一个 bar
s 不是 template
功能。它们是 eaxh 一个具有固定签名的函数,一个新的重载,类似于你写的
void bar(foo<char>){}
在foo
之后.异常(exception)情况是 friend bar
只能通过 ADL 找到,这改变了冲突和重载解决的工作方式。
现在这个:
template<class T>
struct foo {
template <typename X>
friend void bar(foo<X>){}
};
创建一个 template
bar
对于 foo
的每个实例.这些并不冲突,因为它们只能通过 ADL 找到。唯一可以找到的是 T
所在的那个匹配X
(在这种情况下——如果参数更多,它可能会有所不同)。
做 template
很少是个好主意版本,根据我的经验。
关于c++ - 为什么在没有模板声明编译的情况下包含在模板类中使用模板参数的友元函数的实现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29504265/