模板运算符重载函数上的未定义符号

时间:2012-10-31 02:26:42

标签: c++ templates namespaces operator-overloading

我有这个函数声明:

template<class T>
a::A& a::A::operator<<(T out) {
    std::cout << out;
    return (*this);
}

和这个函数定义:

namespace a {
    ...
    class A {
        ...
        template<class T> A& operator<<(T);

我称之为:

a::A b;
b << 1;

这是Makefile:

app: main.o A.o
    g++ main.o A.o -o app

main.o: main.cpp
    g++ -c main.cpp

A.o: A.cpp
    g++ -c A.cpp

它给了我:

  

未定义的符号:a :: A&amp;一个:: A ::运营商LT;&LT; &LT; INT&GT;(int)的

为什么会这样?

2 个答案:

答案 0 :(得分:4)

T表示的类型(即您的情况下为int)实际上已知时,函数模板将在编译时变为实际函数。但是,在main.cpp编译之前不是这种情况。在编译A.cpp时,模板函数未实例化为实际函数,因此生成的目标文件不包含函数的二进制版本。

有两种方法可以解决这个问题。

  1. 在头文件中包含函数定义。也就是说,制作

    template<class T>
    a::A& a::A::operator<<(T out) {
        std::cout << out;
        return (*this);
    }
    

    头文件的一部分,并从.cpp文件中删除函数定义。

    这样做的结果是包含此标头的任何 .cpp文件将能够使用模板的任何实例化,即对于任何值T

  2. 或者,在A.cpp中包含显式模板实例化语句:

    template a::A& a::A::operator<<(int out);
    

    这将导致编译器在编译A.cpp时实际实例化模板,并将编译的函数包含在目标文件中。因此链接器可以在将main.oA.o链接在一起时找到它,一切都很好。缺点是它只适用于您为其提供显式实例化的特定类型(在这种情况下,只有int)。

答案 1 :(得分:-1)

尝试将您的定义更改为:

template<class T>
a::A& a::A::operator<< <T> (T out) {
    std::cout << out;
    return (*this);
}

(确保它在头文件中)