摘要
这个问题是关于在几个不同的翻译单元中实现单个模板类实例的单独编译。
问题
对于非模板类,可以将定义放入多个.cpp文件中,然后分别进行编译。例如:
文件A.h:
class A {
public:
void func1();
void func2();
void func3() { /* defined in class declaration */}
}
文件A1.cpp:
void A::func1() { /* do smth */ }
文件A2.cpp:
void A::func2() { /* do smth else */ }
现在,我尝试对模板类执行类似的操作。由于我确切知道我需要哪些实例,因此我将显式实例化模板。我将分别编译每个实例,因为成员函数包含相当大的数学表达式,这可能会在高优化级别上显着降低编译器的速度。所以我尝试了以下方法:
文件TA.h:
template <typename T>
class TA {
public:
void func1();
void func2();
void func3() { /* defined in class declaration */}
}
文件TA1.cpp:
template <typename T>
void TA<T>::func1() { /* do smth */ }
template class TA<sometype>;
文件TA2.cpp:
template <typename T>
void TA<T>::func2() { /* do smth else */ }
template class TA<sometype>;
它在Linux上适用于clang和GCC,但在链接期间出现重复符号错误(在本示例中,由于func3,在TA1.cpp和TA2.cpp中均已实例化),在Mac上的GCC无法使用。
然后我偶然发现了标准中的这句话:
这是否意味着即使使用显式实例化,模板类的单独编译也是不可能的(不允许)(隐式实例化显然是不可能的)?
PS:我已经知道答案了,所以我不在乎,但是谁认为在这里回答https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file是错误的。
最佳答案
在再次查看该标准之后,在我看来,唯一合理的选择是使用单个显式模板类实例化与少量“困难”函数的显式成员函数实例化相结合。
这(根据14.7.2p9)将实例化该类以及到此为止已定义的所有成员(应包括“困难”成员以外的所有)。然后,可以在包含其定义的其他翻译单元中显式实例化那些选定的成员。
这将使我的示例如下所示(假设TA1.cpp包含简单函数,并且 TA 中唯一的“难”函数是 func2 )
文件TA1.cpp:
template <typename T>
void TA<T>::func1() { /* "simple" function definition */ }
template class TA<sometype>; /* expl. inst. of class */
文件TA2.cpp:
template <typename T>
void TA<T>::func2() { /* "difficult" function definition */ }
template void TA<sometype>::func2(); /* expl. inst. of member */
此方法要求我们为每个“困难”函数编写显式的实例化定义,这很繁琐,但也使我们三思而后行,无论我们是否真的要单独保留它。
免责声明
什么时候有用?不经常。正如这里的其他人所提到的,不建议将类的定义拆分为多个文件。在我的特殊情况下,“难”函数包含对非平凡类的实例的复杂数学运算。 C++模板并没有以快速的编译速度闻名,但是在这种情况下,它是无法忍受的。这些函数互相调用,从而使编译器经历了漫长而费时的内存扩展/内联重载运算符/模板/等的旅程,以优化其所看到的一切,几乎实现了零改善,但使编译可持续了数小时。将某些函数隔离在单独文件中的技巧可将编译速度提高20倍(并使其并行化)。
关于c++ - 单独的编译和模板显式实例化,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21534435/