问题描述
限时送ChatGPT账号..给定以下代码.
#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_;
};
编译器可以轻松编译具有模板参数且没有以下语法的友元函数
The compiler has no trouble compiling both friend functions which have template parameters without having the following syntax
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)
因为它们是由它们在模板类本身内部的实现定义的.
because they have been defined by their implementation inside the template class itself.
编译器如何在不包含模板声明的情况下编译这些带有模板参数的友元函数?为什么只在类中实现它们就足够了?
How can the compiler compile these friend functions with their template parameters without including a template declaration? Why is just having their implementation inside of the class enough?
我从这里的部分了解了这个概念为什么我在使用模板好友时会出现链接器错误?"
I learned about this concept from here under the section on "Why do I get linker errors when I use template friends?"
推荐答案
这两个选项,有和没有 template
,做的事情略有不同.
Those two options, with and without template<class T>
, do slightly different things.
当你以这种方式引入一个 friend
函数时,你在封闭的命名空间中以一种只能通过 ADL(参数依赖查找)访问的方式引入它.
When you introduce a friend
function that way, you introduce it within the enclosing namespace in a way that is only reachable via ADL (argument dependent lookup).
template
引入了函数模板,没有引入了实际函数的模板.
The template<class T>
introduces a function template, and the one without introduces an actual function.
所以:
template<class T>
struct foo {
friend void bar(foo<T>){}
};
表示当foo
存在时,创建一个函数bar(foo
.然后 foo
创建 bar(foo
.
means that when foo<int>
exists, a function bar(foo<int>)
is created. Then foo<double>
creates bar(foo<double>)
.
这些 bar
中的每一个都不是 template
函数.它们是一个具有固定签名的函数,一个新的重载,类似于你写的
Each of these bar
s are not template
functions. They are eaxh a function with a fixed signature, a new overload, imilar to if you wrote
void bar(foo<char>){}
紧跟在 foo
之后.唯一的例外是 friend bar
只能通过 ADL 找到,这改变了冲突和重载解决的工作方式.
right after foo
. The exception is that the friend bar
can only be found via ADL, which changes how conflicts and overload resolution works.
现在这个:
template<class T>
struct foo {
template <typename X>
friend void bar(foo<X>){}
};
为 foo
的每个实例创建一个 template
bar
.这些并不冲突,因为它们只能通过 ADL 找到.唯一可以找到的是 T
与 X
匹配的那个(在这种情况下 - 有更多参数可能会有所不同).
creates a template
bar
for each instance of foo
. These do not conflict, because they are only found via ADL. And the only one that can be found is the one where the T
matches the X
(in this case -- with more arguments it could differ).
根据我的经验,制作 template
版本很少是一个好主意.
It is rarely a good idea to do the template
version, in my experience.
这篇关于为什么在没有模板声明的情况下在模板类中包含使用模板参数的友元函数的实现?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!