模板是如何工作的,它们总是内联吗?

时间:2011-03-25 10:42:43

标签: c++ templates inline

如果内联,我可以理解它是如何工作的。但如果他们不是,它是如何工作的?是否所有目标文件都获得了自己的副本,例如函数模板?

6 个答案:

答案 0 :(得分:4)

模板将以inline的标准含义内联,这与一个定义规则比与实际代码内联更相关。也就是说,如果模板函数是在多个翻译单元中定义的,链接器就不会抱怨,它只会选择一个(注意:随机的,如果你在不同的翻译单元中提供不同的模板定义,当前的编译器不会抱怨!并将其留在最后的二进制文件中。

现在,与所有其他inline函数一样,编译器可以决定实际避免函数调用并在调用地点内联函数是一个好主意,或者它可能确定它不是这样一个好主意(大函数,一些编译器没有嵌套循环函数......无论什么原因)然后它不会执行实际的内联代码。

答案 1 :(得分:2)

取决于编译器,但我看过的每一个都会创建一个函数,然后使用替换模板参数调用该函数来为每个变量生成代码。

作为(非常)简单的例子:

template <typename T> T Max(T a, T b)
{
    return a > b ? a : b;
}

当被调用为Max<int>Max<float>并且没有内联时,编译器会生成(但它们以特殊方式进行修饰,以防止出现其他问题):

int Max(int a, int b)
{
    return a > b ? a : b;
}

float Max(float a, float b)
{
    return a > b ? a : b;
}

然后它停留在对象的开头然后被引用,然后对于某些内联也是如此(在MSVC中)

答案 2 :(得分:2)

这取决于。一些比较流行的实现 在每个目标文件中生成实例化代码的副本 触发实例化,并依赖链接器 扔掉除了一个以外的所有人其他编译器使用某种方式 存储库,存储实例化;如果 实例化已经存在,编译器不会打扰 再生它。此解决方案明显更快且使用 比第一个解决方案更少的磁盘,但它也更难 走吧(编译器必须生成新的实例化 不仅如果一个不存在,而且如果有任何文件的话 实例化取决于已经改变。)

答案 3 :(得分:1)

它依赖于实现。

但通常,是的,每个目标文件都会获得他们使用的每个扩展函数的副本。 然后链接器在链接时注意到这一点并确保只有一个函数副本放入最终的可执行文件中

答案 4 :(得分:0)

模板本身就是一种完整的语言。它们是Turing完整的,但“程序”在编译时运行。它们是代码工厂,它们在编译时替换对象类型,并在编译时汇编类,函数等。因此,您可以将其视为类型安全,C ++兼容的大规模预处理语言。生成的执行输出是纯C ++代码,然后编译器可以像处理其他所有代码一样处理它。

编译器通常会忽略内联,因为很少有程序员能够真正知道什么时候最好,而那些没有离开程序集的人。

答案 5 :(得分:-1)

模板真的是非常高级的MACROS(#define)

参数在编译时被替换为传递的值。真的很棒的概念,并且实施得非常好。