模板化的超类链接问题
Templated superclass linking problem
我正在尝试创建一个带有模板化超类的C++类。这个想法是,我可以很容易地从许多具有相似特性的超类中创建许多相似的子类。
我将有问题的代码提炼如下:
template_test.h
:
template<class BaseClass>
class Templated : public BaseClass
{
public:
Templated(int a);
virtual int Foo();
};
class Base
{
protected:
Base(int a);
public:
virtual int Foo() = 0;
protected:
int b;
};
template_test.cpp
:
#include "template_test.h"
Base::Base(int a)
: b(a+1)
{
}
template<class BaseClass>
Templated<BaseClass>::Templated(int a)
: BaseClass(a)
{
}
template<class BaseClass>
int Templated<BaseClass>::Foo()
{
return this->b;
}
main.cpp
:
#include "template_test.h"
int main()
{
Templated<Base> test(1);
return test.Foo();
}
当我构建代码时,我得到链接器错误,说找不到符号Templated<Base>::Templated(int)
和Templated<Base>::Foo()
。
谷歌快速建议在main.cpp
中添加以下内容将解决问题:
template<> Templated<Base>::Templated(int a);
template<> int Templated<Base>::Foo();
但这并不能解决问题。将行添加到main.cpp
也不起作用。(不过,有趣的是,将它们添加到两者中会导致链接器出现"多重定义符号"错误,所以它们一定在做什么…)
但是,将所有代码放在一个源文件中确实解决了这个问题。虽然这对于上面的noddy示例来说是可以的,但如果我被迫将所有内容放在一个cpp文件中,我正在查看的实际应用程序将很快变得无法管理。
有人知道我所做的是否可能吗?(如何)解决链接器错误?
我假设我可以使class Templated
中的所有方法内联,这将起作用,但这似乎也不理想。
对于模板化类,每个使用它的翻译单元都必须有可用的定义。这些定义可以放在一个单独的文件中,通常扩展名为.inl
或.tcc
;头文件CCD_ 11是位于底部的那个文件。因此,即使它在一个单独的文件中,对于每个翻译单元,它仍然是#include
d;它不可能是独立的。
因此,对于您的示例,将template_test.cpp
重命名为template_test.inl
(或template_test.tcc
,或其他),然后将#include "template_test.inl"
(或其他)放在template_test.h
的底部,刚好在include保护的#endif
之前。
希望这能有所帮助!
问题是,当编译Templated文件时,编译器不知道需要为哪些类型生成代码,所以它不知道。
然后当你链接时,main.cpp说它需要这些函数,但它们从未被编译成对象文件,所以链接器找不到它们。
其他答案显示了以可移植的方式解决这个问题的方法,本质上,将模板化成员函数的定义放在一个可以从实例化该类实例的地方看到的地方——要么通过显式实例化,要么将实现放在main.cpp中#包含的文件中。
您可能还想阅读编译器的文档,看看他们建议如何设置。我知道IBMXLC编译器有一些不同的设置和选项来设置这些设置。
C++FAQ lite涵盖了这一点,以及绕过它的几种方法
您不必使所有方法都"内联",但您应该在template_test.h中定义方法体,而不是在template_ttest.cpp.中定义
有些编译器可以处理这种拆分,但您必须记住,在某种程度上,模板就像宏。为了让编译器为您的特定对象生成模板,它需要有现成的模板源。
当编译器编译main.cpp时,它会看到类定义有成员函数声明,但没有成员函数定义。它只是假设某个地方必须有一个"模板化"构造函数和Foo实现的定义,所以它在链接时听从链接器来找到它。
解决您的问题的方法是将Templateed的实现放入template.h.中
例如
template<class BaseClass>
class Templated : public BaseClass
{
public:
Templated(int a) : BaseClass(a) {}
virtual int Foo() { return BaseClass::b; }
};
有趣的是,我可以把它放在template_test.cpp.的末尾,让你的代码链接起来
void Nobody_Ever_Calls_This()
{
Templated<Base> dummy(1);
}
现在编译器可以找到要链接的Templated实例。我不建议将此作为一种技术。其他一些文件可能想要创建
Templated<Widget>
然后您必须向template_test.cpp.
- 使用jsoncpp库时出现链接问题
- Cmake 链接问题:未定义对 Button::mousePressEvent(QGraphicsSceneMouseE
- 如何将GTest与CMake一起使用?遵循谷歌指南时的链接问题
- 未解决的外部链接问题
- 'make check' GLIBC 运行时的链接问题
- 在树莓派上用libtorch构建程序时的链接问题
- 野牛弹性链接问题
- 与 AWS 开发工具包的链接问题
- Qt & Firebase C++ SDK 在 iOS 上的链接问题
- 链接问题 boost::p ython::numpy.
- 与 32 位共享对象的链接问题
- 在单元测试项目中包括 .c 文件,并从多个 cpp 文件访问它而不会出现链接问题
- 安卓链接问题
- LLVM 传递链接问题:未定义的符号
- Cmake Mac OSX库链接问题:在Linux上进行编译,但在Mac上进行了编译
- 用libclang解析源文件 - 链接问题包括文件
- C / C++链接问题与非常简单的设置
- Zbar 在 vs2015 链接问题
- Vulkan + GLFW + Cmake在Linux环境下的链接问题
- TFS构建由于链接问题而失败