为什么这个静态成员即使存在也没有构造?

时间:2018-08-11 13:50:59

标签: c++ templates inheritance static

前几天,我遇到了一些意外行为,并将其简化为以下几行代码。我在VC ++ 19.0,Clang 3.8和GCC 5.4.0以及8.2.0上进行了测试。在每种情况下,输出仅为1,而我曾期望它以Hello开头并以Goodbye结束。

#include <iostream>

template <class T> struct X { static T data; };
template <class T> T X<T>::data;

struct A
{
    A()
    {
        std::cout << "Hello" << std::endl;
    }

    ~A()
    {
        std::cout << "Goodbye" << std::endl;
    }
};

struct B : X<A> { };

int main(int argc, char **argv)
{
    std::cout << sizeof(B::data) << std::endl;
}

显然B::data存在,但从未调用过其构造函数和析构函数。有趣的是,如果我将其添加到测试中

assert(typeid(B::data) == typeid(A));

GCC的行为符合我最初的预期,但Clang和VC ++的行为均与以前相同。所以我在这里的怀疑是行为是不确定的,而不仅仅是意外的。我对语言标准的措辞还不熟悉,无法为自己准确说明这种情况下的违规行为。但这肯定与我对静态成员和继承如何工作的直觉相抵触。

2 个答案:

答案 0 :(得分:1)

根据[temp.inst]/3

  

...尤其是,除非静态数据成员本身以要求静态数据成员的定义存在的方式使用,否则不会发生静态数据成员的初始化(以及任何相关的副作用)。 / p>

[expr.context]/1

  

[注:在未求值的操作数中,可以将非静态类成员命名为([expr.prim.id]),并且对象或函数的命名本身并不要求提供定义([基本.def.odr])。 ... —注释]

X<A>::data仅用作sizeof的操作数,它是未评估的操作数,因此X<A>::data未初始化。

对于typeid,我认为这是GCC错误。

答案 1 :(得分:0)

访问结构的静态成员不会实例化它,因此永远不会调用struct X<A>的构造函数。

您甚至可以简化代码以尝试不使用模板,因为它不会影响此处的结果。