G++如果模板类构造函数和成员函数的定义与其使用分离,则链接器找不到它们
可能的重复:
为什么模板只能在头文件中实现?< /a>
在开发一个具有某种类型感知功能的小型解析器时,我遇到了以下难题。简而言之:
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 see()
。
编译失败☹
但是,当我尝试使用
g++ *.cpp
(或显式命名文件)编译 C++ 源代码时,我在 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 中的函数定义如果位于同一文件中,则属于模板类。
Possible Duplicate:
Why can templates only be implemented in the header file?
While developing a little parser with some type-awareness, I have come across the following puzzle. In short:
GNU g++ “forgets” a template member function definition unless it is defined in the same file where it is used.
Any ideas why?
The Files of the Case
To isolate the problem, I have stripped down the code to three files:
The header file Temple.hpp:
#ifndef _TEMPLE
#define _TEMPLE
template <class T> class Temple {
private:
T deity;
public:
Temple ( T value );
T see ();
};
#endif
Then the corresponding C++ implementation file Temple.cpp:
#include "Temple.hpp"
template <class T> Temple<T>::Temple ( T value ) : deity( value ) {}
template <class T> T Temple<T>::see () { return deity; }
And finally a main application calling the stuff in a file templetest.cpp:
#include "Temple.hpp"
int main () {
bool b(false);
Temple<bool> t( b );
t.see();
}
What should happen is that a local variable Temple<bool> t
is constructed and then provides the (template-expanded) method bool see()
as defined by the template.
Compilation as it fails ☹
However, when I try to compile the C++ sourcecode using
g++ *.cpp
(or naming the files explicitly, as well), I get a linker error on gcc version 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
and somewhat less verbose on gcc 4.0.1:
/usr/bin/ld: Undefined symbols:
Temple<bool>::see()
Temple<bool>::Temple(bool)
collect2: ld returned 1 exit status
Anyway, from this I conclude that templetest.cpp can access neither the constructor nor a member function of the concrete template class.
Compilation as it works ☻
So far so bad, but there is another way of compiling, namely putting all code into just one source file and then compiling. Surprisingly, this goes well. You can try the approach simply using stdin-streaming:
cat *.cpp | g++ -x c++ -
The same success is the result if the file Temple.cpp is manually merged into Temple.hpp to yield:
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; }
and this is subsequently compiled using
g++ templetest.cpp
It appears that GNU CC can only remember that the member function definitions in Temple.cpp belong to the template class if they are in the same file.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在 main.c 中,当您声明
Temple
类型的变量时,您就实例化了该类型。为了实例化模板化类型,您必须有权访问该类型的所有实现。你有两个选择。
第一个也是传统的选择是将整个实现放在头文件中,并删除 Temple.cpp 文件:
这样,模板的任何用户都可以使用他们选择的任何类型实例化它。
第二种不太传统的方法是在唯一可以访问整个实现的位置(即 Temple.cpp)显式实例化
Temple
:但是,请注意,Temple 的用户模板类
Temple
只能使用您创建的实例。在这种情况下,他们可能只使用bool
。In main.c, at the moment you declare a variable of type
Temple<bool>
, you instantiate that type. In order to instantiate a templated type, you must have access to all of the implementation of that type.You have two choices.
The first, and conventional, choice is to place the entire implementation in the header file, and delete the Temple.cpp file:
This way, any user of your template can instantiate it with any type they choose.
The second, and less conventional, way is to explicitly instantiate
Temple<bool>
in the only location that has access to the entire implementation, namely temple.cpp:Be warned, however, that the users of the templated class
Temple
can only use instances that you have created. In this case, they may only ever usebool
.