类定义中的静态数据成员初始化?

时间:2019-03-19 21:20:55

标签: c++

我在这里有一个问题,所以为什么(为什么?)无法在类内部初始化静态变量? 我所管理的

  

http://eel.is/c++draft/class.static.data#3

     

如果非易失性非内联const静态数据成员是整数   或枚举类型,... 仍应在命名空间范围内定义   如果在程序和名称空间范围定义中使用了它   不得包含初始化程序。

所以,像这样的例子

struct X {
    static int const n = 7; // should be defined outside the class, 
                            // but it's compiles successfully
};

我看到了这个主题https://stackoverflow.com/a/16374286/9780989,有一个这样的例子

struct s
{
    static std::size_t const len = 10;
    int arr[len];
};
std::size_t const s::len; 

带有-

的单词
  

“如果未在类定义中初始化len,则编译器   在下一行无法轻易知道其值来定义长度   的。”

但是实际上没有 std :: size_t const s :: len -这行它也可以成功编译,所以在什么情况下它不起作用? https://gcc.godbolt.org/z/OMKzEO

因此,我们走得更远,为什么我们不能在类内部初始化静态成员,而const限定符允许这样做,为什么没有我们就不能这样做? const允许在类内进行初始化的作用是什么?

您可能会说,由于ODR以及Stroustrup的含义,我们无法在类内部初始化静态成员:

  

通常在头文件中声明一个类,而头文件为   通常包含在许多翻译单元中。但是,要避免   复杂的链接器规则,C ++要求每个对象都有唯一的   定义。如果C ++允许在类中使用,则该规则将被打破   定义需要作为对象存储在内存中的实体。

但这不是事实,为什么编译器会解决以下事实:模板类的静态成员在标头(转换单元之外)中初始化了?

// templates are completely pushed into headers
template<typename T>
struct X {
    static int val;
};  

// here the static member of the template class is initialized in the header  
template<typename T>
int X<T>::val = 0; 

int main() {
    X<int> x;
}

好的,我将尝试具体化我的问题:

  1. 为什么可以在类定义中定义const静态数据成员 (如果未使用,则无需定义 在课外)?
  2. 为什么没有const的静态数据成员可能不是 在类定义中定义(请参阅我对模板的想法 带有静态成员和Stroustrup单词的类(他是否 欺骗我们吗?))?

是的,我看到在C ++ 17中我们允许使用内联,但是我对这种情况不感兴趣。

1 个答案:

答案 0 :(得分:1)

  

为什么(为什么?)无法在类内部初始化静态变量?

不是不可能在类定义中初始化静态变量(如果它们是const)。

  

但是实际上没有std :: size_t const s :: len-这行它也可以成功编译,所以在什么情况下它不起作用?

之所以有效,是因为该变量未被使用。参见[basic.def.odr]:

  

除非其名称显示为可能评估的表达式e的变量x,否则e会使用它,除非

     
      
  • x是参考...
  •   
  • x是非引用类型的变量,可在常量表达式中使用并且没有可变的子对象,并且e是非挥发性限定的非类类型的表达式的潜在结果集中的元素应用左值到右值转换([conv.lval]),或...
  •   

此外,违反ODR的行为无需诊断。从技术上讲,缺少定义是正确的。优化可能会删除odr-uses,以便它们不会表现为错误。

尝试以下操作以使用该变量:

const int *ptr = &X::n;
  
      
  1. 为什么可以在类定义中定义const静态数据成员?
  2.   

不。非内联const静态数据成员不是由类定义中的声明定义的。如果变量是odr-used,则需要在类之外有一个定义。

  
      
  1. 为什么不能在类定义中定义静态数据成员[...](请参阅我对带有静态成员的模板类的想法,以及关于此的Stroustrup词(他欺骗我们吗?))?
  2.   

Stroustrup对于“复杂的链接器规则”是正确的。如果无法在标头中定义静态变量,则可以避免这些情况。

关于模板的观点很有意义。无论如何,都需要那些复杂的链接器规则才能使模板化静态变量成为可能。甚至可以定义非模板静态变量也具有优势。这可能是委员会选择允许在C ++ 17的类定义中定义静态成员的原因。请参阅:inline静态成员定义。