C++ &引用;“不完整”;对象实例化和输出行为

C++ &引用;“不完整”;对象实例化和输出行为,c++,c++17,C++,C++17,下面的代码究竟是如何工作的 #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"); }

下面的代码究竟是如何工作的

#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
  • 它所依据的标准是什么?它只是C++1z吗?我找不到相关的建议。你能给我一个链接吗
  • 此代码中的
    x
    是什么?测试t=x作业实际上是如何工作的
此外,如果我将
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";
}


为什么?

正如其他人已经提到的,您使用了变量模板

如果我没有弄错的话,变量模板类似于以下内容:

template<class T>
struct X {
    static T x;
};

template<class T>
T X<T>::x = T{};
模板
结构X{
静态tx;
};
模板
tx::X=T{};
然后使用它,它将类似于:

void foo() {
    class Test {
    public:
        Test() { std::printf("Test::Test\n"); }
    };

    Test t = X<Test>::x;
}
void foo(){
课堂测试{
公众:
Test(){std::printf(“Test::Test\n”);}
};
试验t=X::X;
}
如果尝试此操作,您将看到相同的结果:

模板在
foo
中实例化,并发出初始化静态成员的代码。 此初始化发生在运行
main
之前,因此您会看到首先打印的
Test::Test

至于初始化,尽管使用变量的代码从未被调用-我想编译器可以尝试推断整个程序中从未调用
foo
Test
是一个本地类,其类型不会转义
foo
,因此,使实例化
X::X
对其他任何人都不可访问,并决定将其删除

…但我想这需要在链接时付出一些努力,而我看不到标准规定的这种行为


此外,我不确定编译器/链接器是否允许删除非局部变量的初始化,如果该初始化有副作用。

Google“variable template”。@sleep tight pupper好的,谢谢。为什么它实例化了对
foo
函数的w/o调用?:“除非变量模板专门化已显式实例化或显式专门化,否则在使用专门化时,变量模板专门化将隐式实例化”
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;
}