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

Sho*_*hoe 3 c++ templates namespaces operator-overloading

我有此函数声明:

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

和此函数定义:

namespace a {
    ...
    class A {
        ...
        template<class T> A& operator<<(T);
Run Code Online (Sandbox Code Playgroud)

我称之为:

a::A b;
b << 1;
Run Code Online (Sandbox Code Playgroud)

这是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
Run Code Online (Sandbox Code Playgroud)

它给了我:

未定义的符号:a :: A&a :: A :: operator << <int>(int)

这是为什么?

jog*_*pan 5

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

有两种解决方法。

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

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

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

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

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

    template a::A& a::A::operator<<(int out);
    
    Run Code Online (Sandbox Code Playgroud)

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