如果模板类构造函数和成员函数的定义与使用分离,则G++链接器找不到它们

G++ linker does not find template class constructor and member function if their definition is separated from their use

本文关键字:分离 G++ 链接 找不到 构造函数 成员 定义 函数 如果      更新时间:2023-10-16

可能重复:
为什么模板只能在头文件中实现?

在开发一个具有某种类型意识的小解析器时,我遇到了以下难题。简而言之:

GNU g++"忘记"模板成员函数定义,除非它是在使用它的同一文件中定义的

有什么想法吗?

案件档案

为了隔离这个问题,我将代码分解为三个文件:

头文件Temple.hpp:

#ifndef _TEMPLE
#define _TEMPLE
template <class T> class Temple {
    private:
        T deity;
    public:
        Temple ( T value );
        T see ();
};
#endif

然后是相应的C++实现文件Temple.cpp:

#include "Temple.hpp"
template <class T> Temple<T>::Temple ( T value ) : deity( value ) {}
template <class T> T Temple<T>::see () { return deity; }

最后是一个主应用程序调用文件templetst.cpp:中的内容

#include "Temple.hpp"
int main () {
    bool b(false);
    Temple<bool> t( b );
    t.see();
}

应该发生的是,构造一个局部变量Temple<bool> t,然后提供由模板定义的(模板扩展的(方法bool see()

编译失败☹

然而,当我尝试使用编译C++源代码时

g++ *.cpp

(或者显式地命名文件(,我在gcc版本4.2.1上得到了一个链接器错误:

/tmp//ccWAFJDF.o(.text+0x24): In function `main':
: undefined reference to `Temple<bool>::Temple(bool)'
/tmp//ccWAFJDF.o(.text+0x2f): In function `main':
: undefined reference to `Temple<bool>::see()'
collect2: ld returned 1 exit status

并且在gcc 4.0.1上稍微不那么冗长:

/usr/bin/ld: Undefined symbols:
Temple<bool>::see()
Temple<bool>::Temple(bool)
collect2: ld returned 1 exit status

无论如何,从这里我得出结论,templetest.cpp既不能访问构造函数,也不能访问具体模板类的成员函数。

编译工作☻

到目前为止还很糟糕,但还有另一种编译方法,即将所有代码放入一个源文件中,然后进行编译。令人惊讶的是,进展顺利。您可以简单地使用stdin流式传输尝试这种方法:

cat *.cpp | g++ -x c++ -

如果将文件Temple.cpp手动合并到Temple.hpp中以产生,则会获得同样的成功

template <class T> class Temple {
    private:
        T deity;
    public:
        Temple ( T value );
        T see ();
};
template <class T> Temple<T>::Temple ( T value ) : deity( value ) {}
template <class T> T Temple<T>::see () { return deity; }

然后使用进行编译

g++ templetest.cpp

GNU CC似乎只能记住Temple.cpp中的成员函数定义属于模板类,如果它们在同一文件中的话。

在main.c中,在声明Temple<bool>类型的变量时,实例化该类型。为了实例化模板化类型,您必须能够访问该类型的所有实现。

你有两个选择。

第一个也是传统的选择是将整个实现放在头文件中,并删除Temple.cpp文件:

// UNTESTED
template <class T> class Temple {
  private:
    T deity;
  public:
    Temple ( T value ) : deity(value) {}
    T see () { return deity; }
};

这样,模板的任何用户都可以用他们选择的任何类型来实例化它。

第二种也是不太传统的方法是在唯一可以访问整个实现的位置显式实例化Temple<bool>,即temple.cpp:

// temple.cpp
...
// At the very end of the file:
template class Temple<bool>;

但是,请注意,模板类Temple的用户只能使用您创建的实例。在这种情况下,他们只能使用bool