简体   繁体   English

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

[英]Static data member initialization in the class definition?

I had one question here, so, why (for what?) it is impossible to initialize the static variable inside the class ? 我在这里有一个问题,那么, 为什么(为什么?)在类中初始化静态变量是不可能的 What I managed 我管理的是什么

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

If a non-volatile non-inline const static data member is of integral or enumeration type, ... shall still be defined in a namespace scope if it is odr-used in the program and the namespace scope definition shall not contain an initializer. 如果非挥发性非内联常数静态数据成员是整型或枚举类型的,... 仍应在命名空间范围限定 ,如果它在程序ODR使用的和命名空间范围定义不应含有一个初始化。

So, example like this 所以,像这样的例子

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

I see this topic https://stackoverflow.com/a/16374286/9780989 , there was given such an example 我看到这个话题https://stackoverflow.com/a/16374286/9780989 ,给出了这样一个例子

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

with words that, - 用这个词, -

"If len wasn't initialized in the class definition, the compiler couldn't easily know its value in the next line to define the length of arr." “如果len未在类定义中初始化,则编译器无法在下一行中轻松知道其值以定义arr的长度。”

But actually without std::size_t const s::len - this line it's compiles successfully too, so in what cases it shouldn't work? 但实际上没有std :: size_t const s :: len - 这行也是成功编译的,所以在什么情况下它应该不起作用? https://gcc.godbolt.org/z/OMKzEO https://gcc.godbolt.org/z/OMKzEO

And so we go further, why we can't initialize static members inside the class, const qualifier allow this, why without we can't do it? 所以我们走得更远,为什么我们不能初始化类里面的静态成员,const限定符允许这个,为什么没有我们做不到呢? What does const do that allows initialization inside a class? const做什么允许在类中进行初始化?

You may said that we can't initialize static members inside the class, because of ODR and that what says Stroustrup: 您可能会说我们无法初始化类中的静态成员,因为ODR和Stroustrup的内容:

A class is typically declared in a header file and a header file is typically included into many translation units. 类通常在头文件中声明,并且头文件通常包含在许多翻译单元中。 However, to avoid complicated linker rules, C++ requires that every object has a unique definition. 但是,为避免复杂的链接器规则,C ++要求每个对象都有唯一的定义。 That rule would be broken if C++ allowed in-class definition of entities that needed to be stored in memory as objects. 如果C ++允许将需要作为对象存储在内存中的实体的类内定义,则该规则将被破坏。

but it's not true, why than compilers resolve the fact that the static member of the template class is initialized in the header (outside the translation unit)? 但事实并非如此,为什么编译器会解决模板类的静态成员在标题中(在翻译单元之外)初始化的原因?

// 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;
}

Okay, I'll try to concretize my questions: 好的,我会尝试将我的问题具体化:

  1. Why const static data members may be defined in the class definition (and if it non odr-used, then it doesn't needed to be defined outside the class)? 为什么可以在类定义中定义const静态数据成员(如果它没有使用,那么它不需要在类外定义)?
  2. Why static data members without const may not be defined in the class definition (see my thoughts about template classes with static members and Stroustrup words about this (does he cheat us?))? 为什么没有const的静态数据成员可能没有在类定义中定义(请参阅我对有静态成员的模板类和关于此的Stroustrup单词的看法(他是否欺骗了我们?))?

And yes, I see that in C++17 we allow to use inline but I'm less interested in this case. 是的,我看到在C ++ 17中我们允许使用内联,但我对这种情况不太感兴趣。

why (for what?) it is impossible to initialize the static variable inside the class? 为什么(为了什么?)在类中初始化静态变量是不可能的?

It is not impossible to initialise static variables inside the class definition, if they are const. 如果它们是const,那么在类定义中初始化静态变量并非不可能。

But actually without std::size_t const s::len - this line it's compiles successfully too, so in what cases it shouldn't work? 但实际上没有std :: size_t const s :: len - 这行也是成功编译的,所以在什么情况下它应该不起作用?

It works because the variable was not odr-used. 它的工作原理是因为变量没有使用过。 See [basic.def.odr]: 见[basic.def.odr]:

A variable x whose name appears as a potentially-evaluated expression e is odr-used by e unless 变量x的名称显示为潜在评估的表达式e,除非是e使用

  • x is a reference ... x是参考...
  • x is a variable of non-reference type that is usable in constant expressions and has no mutable subobjects, and e is an element of the set of potential results of an expression of non-volatile-qualified non-class type to which the lvalue-to-rvalue conversion ([conv.lval]) is applied, or ... x是非引用类型的变量,可用于常量表达式并且没有可变子对象,并且e是非易失性限定非类型表达式的潜在结果集合的元素,其中左值 - 应用to-rvalue转换([conv.lval]),或者......

Besides, ODR violations are no diagnostic required . 此外,ODR违规无需诊断 This is technically true for missing definitions. 对于缺少定义,这在技术上是正确的。 An optimisation might remove odr-uses so that they don't manifest as errors. 优化可能会删除odr-uses,因此它们不会显示为错误。

Try the following to odr-use the variable: 尝试使用以下内容来使用变量:

const int *ptr = &X::n;
  1. Why const static data members may be defined in the class definition? 为什么可以在类定义中定义const静态数据成员?

No. Non-inline const static data members are not defined by the declaration in the class definition. 否。非内联const静态数据成员不是由类定义中的声明定义的。 There needs to be a definition (outside the class) if the variable is odr-used. 如果变量使用了odr,则需要有一个定义(在类外)。

  1. Why static data members [...] may not be defined in the class definition (see my thoughts about template classes with static members and Stroustrup words about this (does he cheat us?))? 为什么静态数据成员[...]可能没有在类定义中定义(请参阅我对静态成员的模板类和关于此的Stroustrup单词的看法(他是否欺骗了我们?))?

Stroustrup is correct about "complicated linker rules". Stroustrup对于“复杂的链接器规则”是正确的。 Those were avoided when it was not possible to define static variables in headers. 当无法在头文件中定义静态变量时,可以避免这些。

Your point about templates makes sense. 关于模板的观点是有道理的。 Those complicated linker rules were needed anyway to make templated static variables possible. 无论如何都需要那些复杂的链接器规则来使模板化的静态变量成为可能。 And being able to define even non-templated static variables has advantages. 并且能够定义甚至非模板化的静态变量也具有优势。 These are probably the reasons why the committee chose to allow defining static members in class definition in C++17. 这些可能是委员会选择允许在C ++ 17中定义类定义中的静态成员的原因。 See: inline static member definition. 请参阅: inline静态成员定义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM