C++中的模板参数存储在哪里?

5
假设我们有一个A类:
template<int N>
class A final{
public:
    void foo() const { cout << N << endl; }
};
2个回答

8
N本身不会被存储在任何地方,它被编码成类型。从这个角度来看,模板特化A<1>与非模板类A1相同。对于A<2020>{}.foo(),你可能会得到与std::cout << 2020相同的汇编代码。当然,常量2020必须被存储在某个地方,但它不会成为A<2020>{}对象的一部分。

编译后,根据目标架构,A<2020>{}.foo()可能看起来像这样(x86-64):

mov     esi, 2020
mov     edi, OFFSET FLAT:_ZSt4cout
call    std::basic_ostream<char, std::char_traits<char> >::operator<<(int)

这里N直接放入寄存器中。

或者(ARM):

ldr     r1, .L4
ldr     r0, .L4+4
bl      std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
...
.L4:
.word   2020
.word   _ZSt4cout

这里的N是从某个内存位置加载的。

汇编演示


这是否意味着我可以拥有多个A<2020>实例,而“2020部分”只会被定义/存储一次? - luizfls
1
@luizfls,基本上是这样的。例如,如果您有一个包含1'000'000个A<2020>实例的向量,2020不会在内存中重复1'000'000次。 - Evg

4
通常来说,使用模板的好处在于模板本身不会消耗运行时性能,也不会在运行时占用内存空间。因为它们已经在编译时完全处理和评估过了,所以它们甚至在运行时都不存在了。
因此,模板本身消耗性能和空间的唯一时机是在编译时。
然而,模板在编译时生成的代码在运行时当然会占用空间。如果模板被实例化多次,则代码也会被多次生成,每次为程序使用的一组模板参数生成一次代码。代码大小的增加也可能对性能产生负面影响,因为CPU指令缓存可以更好地缓存少量的代码,而不是大量的代码。
回答您的问题:
在运行时,模板本身和它们的参数既不存储在堆上也不存储在栈上,因为它们已经不存在了。只有在编译时,模板和它们的参数才会在编译器的堆或栈中存储。然而,编译器的内部对您没有任何兴趣(除非您计划编写自己的编译器)。
但是,在您的示例中,您问题中的N值仍将存储在程序中的某个位置。但它不会作为模板参数存储,而是作为模板在编译时评估的结果以立即值的形式存储在可执行代码中。实际上,它可能也会在程序的堆栈中某个时刻被存储,因为在您的示例中,它被传递为函数调用的参数。然而,函数参数是通过堆栈还是CPU寄存器传递取决于您使用的平台。

1
首先,它会占用空间,因为每个实例都被存储在“某个地方”。因此,如果按照Evg的答案创建多个实例,将在可执行文件中多次生成指令,在这种情况下,比起在数组或其他地方存储运行时使用的数据,成本要高得多。因此,如果以这种方式使用模板,则可能非常昂贵。因此,感觉你的答案只是指向了错误的方向。 - Klaus
1
@Klaus:是的,你说得有道理。这就是为什么我现在编辑了我的答案,并插入了一个额外的段落来解决你的问题。在第三段中,我现在指出多次实例化模板也可能会在运行时产生负面影响,无论是在代码大小还是性能方面。 - Andreas Wenzel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接