"Incomplete" 对象实例化和输出行为
"Incomplete" object instantiation and output behavior
下面的代码是如何工作的?
#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
?
- 它依赖于哪个标准?它只是 C++1z 吗?我找不到相关的提案。可以给我一个link吗?
- 此代码中的
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
为什么?
正如其他人已经提到的,您使用了变量模板。
如果我没记错的话,变量模板类似于这样的东西:
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
从未被调用整个程序,Test
是一个本地 class,其类型不会转义 foo
,因此使实例化 X<Test>::x
对其他任何人都无法访问,并决定将其删除...
...但我想这在 link 时需要一些努力,而且我没有看到标准强制要求这种行为。
此外,我不确定 compiler/linker 是否允许删除非局部变量的初始化,如果该初始化有副作用。
下面的代码是如何工作的?
#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
? - 它依赖于哪个标准?它只是 C++1z 吗?我找不到相关的提案。可以给我一个link吗?
- 此代码中的
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
为什么?
正如其他人已经提到的,您使用了变量模板。
如果我没记错的话,变量模板类似于这样的东西:
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
从未被调用整个程序,Test
是一个本地 class,其类型不会转义 foo
,因此使实例化 X<Test>::x
对其他任何人都无法访问,并决定将其删除...
...但我想这在 link 时需要一些努力,而且我没有看到标准强制要求这种行为。
此外,我不确定 compiler/linker 是否允许删除非局部变量的初始化,如果该初始化有副作用。