您不能以这种方式分离声明和定义:如果您将专用成员函数的定义放在单独的.cpp
文件中,无论您是否在主模板之后立即声明您的专业化,编译器都将无法实例化它,并且链接器将抱怨未解析的引用。
通常,类模板的成员函数的定义位于头文件中,unless你提供一个明确的实例化对于相应的类模板:
template class X<int>; // You should add this to make your program build,
// or instantiate the corresponding class template
// specialization and invoke the foo() method in the
// same translation unit (A.cpp)
一般来说,除非你面临really可怕的编译时间问题,我建议您遵循常见做法,将所有内容放入头文件中,以便由所有需要使用类模板的翻译单元包含:
///////////////////// file A.hpp /////////////////////
#include <iostream>
template <typename T>
class A
{
public:
void foo()
{
std::cerr << "error: called generic foo " << std::endl ;
}
};
template <>
void A< int >::foo()
{
std::cerr << "calling <int> version of foo" << std::endl;
}
///////////////////// file main.cpp /////////////////////
#include "A.hpp"
int main(int argc , char** argv)
{
A<int>* a = new A<int>();
a->foo();
return 0;
}
如果您面临非常可怕的编译时间问题,那么您可以将成员函数定义分开,并将它们放入具有显式实例化的单独翻译单元中,但在 C++11 中,没有干净/简单的方法来确保您的所有专业化分别降级.cpp
文件在主模板之后立即声明(正如良好实践所建议的那样)。如果有的话,我想它会很受欢迎,你就不需要来这里询问了,因为大家面临这样的设计问题。
在某些情况下,一些奇特的宏可能会有所帮助,但令人怀疑的是,在真正复杂的项目中,它们会带来比维护痛苦更多的好处。
C++03 标准尝试解决这个问题,引入了export
关键字,但是实现经验证明编译器厂商支持太难了,这就是为什么export
不再是 C++ 标准的一部分(自 C++11 起)。
希望有更好的解决方案modules将其纳入C++14并提供模板设计的解决方案。