为什么在没有模板声明编译的情况下包含在模板 class 中使用模板参数的友元函数的实现?
Why is including implementation for a friend function that uses template parameters inside of a template class without a template declaration compile?
给定以下代码。
#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)
因为它们已由模板 class 本身的实现定义。
编译器如何在不包含模板声明的情况下使用模板参数编译这些友元函数?为什么只在 class 中实现它们就足够了?
我从 "Why do I get linker errors when I use template friends?"
部分的 here 了解到这个概念
这两个选项,有和没有 template<class T>
,做的事情略有不同。
当您以这种方式引入 friend
函数时,您将以一种只能通过 ADL(参数相关查找)访问的方式在封闭的命名空间中引入它。
template<class T>
介绍的是功能模板,没有的介绍的是实际功能。
所以这个:
template<class T>
struct foo {
friend void bar(foo<T>){}
};
表示当foo<int>
存在时,创建一个函数bar(foo<int>)
。然后 foo<double>
创建 bar(foo<double>)
.
这些 bar
中的每一个都不是 template
函数。它们是 eaxh 一个具有固定签名的函数,一个新的重载,类似于你写的
void bar(foo<char>){}
紧接着 foo
。例外是 friend bar
只能通过 ADL 找到,这改变了冲突和重载解决的工作方式。
现在这个:
template<class T>
struct foo {
template <typename X>
friend void bar(foo<X>){}
};
为 foo
的每个实例创建一个 template
bar
。这些并不冲突,因为它们只能通过 ADL 找到。唯一可以找到的是 T
与 X
匹配的那个(在这种情况下——如果有更多参数,它可能会有所不同)。
根据我的经验,template
版本很少是个好主意。
给定以下代码。
#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)
因为它们已由模板 class 本身的实现定义。
编译器如何在不包含模板声明的情况下使用模板参数编译这些友元函数?为什么只在 class 中实现它们就足够了?
我从 "Why do I get linker errors when I use template friends?"
部分的 here 了解到这个概念这两个选项,有和没有 template<class T>
,做的事情略有不同。
当您以这种方式引入 friend
函数时,您将以一种只能通过 ADL(参数相关查找)访问的方式在封闭的命名空间中引入它。
template<class T>
介绍的是功能模板,没有的介绍的是实际功能。
所以这个:
template<class T>
struct foo {
friend void bar(foo<T>){}
};
表示当foo<int>
存在时,创建一个函数bar(foo<int>)
。然后 foo<double>
创建 bar(foo<double>)
.
这些 bar
中的每一个都不是 template
函数。它们是 eaxh 一个具有固定签名的函数,一个新的重载,类似于你写的
void bar(foo<char>){}
紧接着 foo
。例外是 friend bar
只能通过 ADL 找到,这改变了冲突和重载解决的工作方式。
现在这个:
template<class T>
struct foo {
template <typename X>
friend void bar(foo<X>){}
};
为 foo
的每个实例创建一个 template
bar
。这些并不冲突,因为它们只能通过 ADL 找到。唯一可以找到的是 T
与 X
匹配的那个(在这种情况下——如果有更多参数,它可能会有所不同)。
根据我的经验,template
版本很少是个好主意。