qdi*_*dii 1 c++ linker gcc templates template-function
这是一个非常简短的片段,不能用g ++ 4.7.1编译(顺便说一下,它不能用gcc 4.6.3编译).
#include <iostream>
template<typename T>
struct Foo
{
template<typename U>
friend std::ostream& operator<<(Foo&, U&);
};
template<typename T, typename U>
std::ostream& operator<<(Foo<T> foo, U& u)
{
std::cout << u;
return std::cout;
}
int main()
{
Foo<int> f;
f << "bar";
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这就是gcc 4.7.1输出(4.6.3几乎相同的东西).
/tmp/ccNWJW6X.o:在函数
main': main.cpp:(.text+0x15): undefined reference tostd :: basic_ostream>&operator <<(Foo&,char const(&)[4])'collect2:ld返回1退出状态
有谁能解释为什么?
编辑
我也尝试过clang 3.1,它说的完全一样.
与模板的友谊可能有点复杂...让我们看看你的代码做了什么:
template<typename T>
struct Foo {
template<typename U>
friend std::ostream& operator<<(Foo&, U&); // [1]
};
template<typename T, typename U>
std::ostream& operator<<(Foo<T> foo, U& u) { // [2]
std::cout << u;
return std::cout;
}
Run Code Online (Sandbox Code Playgroud)
当您Foo使用类型进行实例化时,例如int[1]中的friend声明声明了一个模板函数:
template <typename U>
std::ostream& operator<<(Foo<int>&,U&);
Run Code Online (Sandbox Code Playgroud)
但是这个函数在任何地方都不存在,你在[2]中提供的是一个带有两个参数的模板:
template<typename T, typename U>
std::ostream& operator<<(Foo<T> foo, U& u);
Run Code Online (Sandbox Code Playgroud)
关键点是在实例化模板时处理好友声明,并且此时Foo表示使用当前实例化获得的类型.
你想做什么有不同的选择,最简单的是将朋友声明改为:
template<typename W, typename U>
friend std::ostream& operator<<(Foo<W> foo, U& u);
Run Code Online (Sandbox Code Playgroud)
这里声明了一个模板,以两个参数(包括W与U不作承诺这里),和你的定义在命名空间级别相匹配.
另一个选项是在类模板定义中定义友元函数,在这种情况下,您可以维护原始签名.有关不同替代方案的更多信息,请查看其他答案