这个问题已经在这里有了答案:




9年前关闭。






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

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; }

最后是一个主应用程序,它在文件Templetest.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-streaming尝试该方法:
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.cpp)中显式实例化Temple<bool>:
// temple.cpp
...
// At the very end of the file:
template class Temple<bool>;

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

09-25 17:09