4

我有这个函数声明:

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& a::A::operator<< <int>(int)

这是为什么?

4

2 回答 2

6

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您为其提供显式实例化的特定类型(在本例中,仅适用于 )。

于 2012-10-31T02:43:51.367 回答
-1

尝试将您的定义更改为:

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

?

(确保它在头文件中)

于 2012-10-31T02:49:21.010 回答