C++编译器如何优化模板代码?

tsk*_*zzy 8 c++ templates

编译器如何通过模板的每个新类型实例化来避免编译二进制文件大小的线性增长

我没有看到当使用新的实例化时我们如何避免复制所有模板化代码.

我觉得编译时间和二进制大小对于除了相当大的代码库中最简单的模板之外的所有人来说都是非常笨重的.但是它们的流行表明编译器能够做一些魔术来使它们变得实用.

Mar*_*som 6

许多模板功能是足够小,有效地串联,所以你得到二元线性增长-但它是没有比你更会用同等的非模板函数得到.

一个定义规则在这里很重要,因为它允许编译器假设具有相同模板参数的任何模板实例化生成相同的代码.如果它检测到模板函数早先已在源文件中实例化,则它可以使用该副本而不是生成新副本.名称修改使链接器可以从不同的编译源识别相同的函数.这些都不能保证,因为您的程序不能区分函数的相同副本之间的区别,但编译器每天都会做比这更难的优化.

需要过滤重复的一次是当函数包含静态变量时 - 只能有一个副本.但这可以通过过滤掉重复的函数或过滤掉静态变量本身来实现.


Die*_*ühl 5

有多种因素会导致多个实例化对exacutable大小没有太大的危害:

  1. 许多模板只是将事物传递到另一层.尽管可能存在相当多的代码,但在代码实例化和内联时,它们大多会消失.注意内联[并进行一些优化]很容易导致更大的代码.请注意,内联函数通常会导致更小(和更快)的代码(主要是因为其他必要的调用序列通常需要比内联更多的指令,并且优化器通过更全面的视图来进一步减少代码的更好机会上).
  2. 在没有内联模板代码的情况下,不同翻译单元中的重复实例化需要合并到一个实例中.我不是链接器专家,但我的理解是,例如,ELF使用不同的部分,链接器可以选择仅包括实际使用的那些部分.
  3. 在较大的可执行文件中,您需要一些词汇类型和实例,这些词汇类型和实例在许多地方使用并有效地共享.使用自定义类型执行所有操作都是不好的主意,类型擦除肯定是避免类型太多的重要工具.

也就是说,在可能的情况下,它会预先实例化模板,特别是如果通常只使用少量的瞬时.一个很好的例子是IOStreams库,它不太可能与超过4种类型一起使用(通常它只与一个一起使用):将模板定义及其实例化移动到单独的转换单元中可能不会减少可执行文件的大小,但肯定会减少编译时间!从C++ 11开始,可以声明模板实例化extern,允许定义可见,而不会在已知在其他地方实例化的特化上进行隐式实例化.