以下代码如何正常工作?
#include <cstdio>
template<class T>
T x = T{};
void foo()
{
class Test
{
public:
Test() { std::printf("Test::Test\n"); }
};
Test t = x<Test>;
}
int main()
{
std::printf("main\n");
}
输出
Test::Test
main
Test::Test
而不是main
?x
是什么以及Test t = x<Test>
分配的实际工作方式是什么?此外,如果我将std::printf
调用更改为std::cout
,则整个程序崩溃:
#include <iostream>
template<class T>
T x = T{};
void foo()
{
class Test
{
public:
Test() { std::cout << "Test::Test\n"; }
};
Test t = x<Test>;
}
int main()
{
std::cout << "main\n";
}
输出
Segmentation fault (core dumped) ./a.out
为什么?
答案 0 :(得分:3)
正如其他人已经提到的那样,你使用了一个变量模板。
如果我没有弄错,变量模板类似于以下内容:
template<class T>
struct X {
static T x;
};
template<class T>
T X<T>::x = T{};
然后使用它,类似于:
void foo() {
class Test {
public:
Test() { std::printf("Test::Test\n"); }
};
Test t = X<Test>::x;
}
如果您尝试此操作,则会看到相同的结果:coliru。
模板在foo
中实例化,并发出初始化静态成员的代码。
此初始化在main
运行之前发生,因此您首先看到Test::Test
打印。
尽管使用了永远不会被调用的变量的代码发生了初始化 - 我假设编译器可能试图推断永远不会在整个程序中调用foo
,{ {1}}是一个本地类,其类型不会转义Test
,从而使实例化foo
无法访问任何其他人,并决定将其删除...
...但我想这需要在链接时付出一些努力,而且我不会看到标准规定的这种行为。
另外,我不确定编译器/链接器是否允许删除非局部变量的初始化,如果该初始化有副作用。