为什么模板函数不能编译?

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,它说的完全一样.

Dav*_*eas 8

与模板的友谊可能有点复杂...让我们看看你的代码做了什么:

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)

这里声明了一个模板,以两个参数(包括WU不作承诺这里),和你的定义在命名空间级别相匹配.

另一个选项是在类模板定义中定义友元函数,在这种情况下,您可以维护原始签名.有关不同替代方案的更多信息,请查看其他答案