单独的汇编和模板显式实例化

Separate compilation and template explicit instantiation

本文关键字:实例化 汇编 单独      更新时间:2023-10-16

摘要
这个问题是关于在几个不同的翻译单元中实现单个模板类实例化的单独汇编。

问题
对于非模板类,可以将定义放在几个.cpp文件中并单独编译。例如:

文件A.H:

class A {
public:
  void func1();
  void func2();
  void func3() { /* defined in class declaration */}
}

file a1.cpp:

void A::func1() { /* do smth */ }

文件A2.CPP:

void A::func2() { /* do smth else */ }

现在,我尝试在模板类中做类似的事情。由于我确切地知道我需要哪些实例,因此我明确实例化模板。我正在分别编译每个实例化,因为成员函数包含相当大的数学表达式,这可能会在高优化水平上大大减慢编译器。所以我尝试了以下内容:

file ta.h:

template <typename T>
class TA {
public:
  void func1();
  void func2();
  void func3() { /* defined in class declaration */}
}

file ta1.cpp:

template <typename T>
void TA<T>::func1() { /* do smth */ }
template class TA<sometype>;

file ta2.cpp:

template <typename T>
void TA<T>::func2() { /* do smth else */ }
template class TA<sometype>;

它与Linux上的Clang和GCC一起使用,但在重复符号错误期间链接时与Mac上的GCC失败(在此示例中,由于func3,该示例在TA1.CPP和TA2.CPP中都进行了实例化)。

)。

然后我在标准中偶然发现了这句话:

C 11.14.7,第5段:
对于给定的模板和一组给定的模板arguments,
- 明确的实例化定义最多应在一个程序中出现,
- ...

这是否意味着即使使用显式实例化,也无法(不允许)单独的模板类的汇编(显然是不可能使用隐式实例化的)?

ps我不在乎,因为我得到了答案,但是谁认为在这里回答的人https://stackoverflow.com/questions/495021/why-can-templates-only-only-only-be-implemented in - 头部文件是错误的。

又一次查看标准后,在我看来,唯一合理的选择是使用单个显式模板类实例化与少数"困难"函数的显式成员函数实例化结合。

此(根据14.7.2p9)将实例化类和所有已定义的成员(到目前为止)(其中应包括所有内容"困难"成员)。那么这些选定的成员可以在包含其定义的其他翻译单元中明确实例化。

这会使我的示例看起来像下面(假设 ta1.cpp 包含简单的功能,并且 ta 中唯一的"困难"功能是 func2

file ta1.cpp:

template <typename T>
void TA<T>::func1() { /* "simple" function definition */ }
template class TA<sometype>; /* expl. inst. of class */

file ta2.cpp:

template <typename T>
void TA<T>::func2() { /* "difficult" function definition */ }
template void TA<sometype>::func2(); /* expl. inst. of member */

此方法要求我们为每个"困难"功能编写明确的实例化定义,这很繁琐,但也使我们三思而后行。

免责声明

什么时候有用?不经常。正如这里提到的其他人所述,不建议将类的定义分为几个文件。在我的特殊情况下,"困难"功能包含了关于非平凡类实例的复杂数学操作。C 模板并不以快速汇编速度而闻名,但在这种情况下,它是难以忍受的。这些功能相互调用,该功能会在扩展/内部嵌入式运算符/模板/等的长时间内存和耗费的旅程中发送编译器,以优化其所看到的所有内容,并有所改善,但要持续数小时。在单独文件中隔离某些函数的这种窍门速度将汇编加速20次(并同样可以并行化)。

模板的单独汇编很棘手,但允许。您不能做的是明确实例化多个翻译单元中的类型,就像不能在两个翻译单元中定义相同函数的方式一样。