为什么我不能在类中初始化非const静态成员或静态数组? [英] Why I can't initialize non-const static member or static array in class?

查看:2877
本文介绍了为什么我不能在类中初始化非const静态成员或静态数组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么我不能在类中初始化非常量 static 成员或 static

  class A 
{
static const int a = 3;
static int b = 3;
static const int c [2] = {1,2};
static int d [2] = {1,2};
};

int main()
{
A a;

return 0;
}

编译器发出以下错误:

  g ++ main.cpp 
main.cpp:4:17:error:ISO C ++禁止非const静态成员'b'的类初始化
main.cpp:5:26:error:在'{'token
main.cpp:5:33:错误:无效的静态数据成员的类的初始化之前不允许括号括起来的初始化器非整数类型'const int [2]'
main.cpp:6:20:错误:在'{'token
main.cpp:6:27之前不允许包含括号的初始化器:错误:非整数类型的静态数据成员的无效类初始化'int [2]'

我有两个问题:


  1. 为什么我不能初始化 static 数据成员在类中

  2. 为什么我不能在类中初始化 static const 数组?


解决方案>

为什么我无法在类中初始化 static 数据成员?



C ++标准只允许静态常量积分或枚举类型在类中初始化。这是允许初始化 a 的原因,而其他则不是。



参考:

C ++ 03 9.4.2静态数据成员

§4


如果静态数据成员是const整数或const枚举类型,它在类定义中的声明可以指定一个常量初始化器,它应该是一个整数常数表达式(5.19)。在这种情况下,成员可以出现在整数常数表达式中。




如果在程序中使用的命名空间范围定义不包含初始化程序, > 什么是整型?



C ++ 03 3.9.1基本类型 b§7


类型bool,char,wchar_t,有符号和无符号整数类型统称为整数类型。积分型是整数型。


注意:


43)因此,枚举(7.2)不是整数;但是,枚举可以提升为int,unsigned int,long或unsigned long,如4.​​5中所述。




解决方法: h2>

您可以使用枚举技巧在类定义中初始化数组。

  class A 
{
static const int a = 3;
enum {arrsize = 2};

static const int c [arrsize] = {1,2};

};



为什么标准不允许这样?



Bjarne适当地解释了这一点 此处


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




为什么只有 static const 整型类型&枚举允许在类初始化?



答案隐藏在Bjarne的引用中,仔细阅读,

C ++要求每个对象如果C ++允许需要在内存中存储为对象的实体的类定义,则该规则将被破坏。



请注意,只有 static const 整数可以被视为编译时常量。编译器知道整数值不会随时改变,因此它可以应用自己的魔法并应用优化,编译器简单地简化这样的类成员,即它们不再存储在存储器中。由于存储在存储器中的需要被去除,它给这样的变量Bjarne提到的规则的例外。



值得注意的是,即使 static const 整数值可以具有同级初始化,的这些变量是不允许的。一个可以取静态成员的地址,如果(并且只有)它有一个超类的定义。这进一步验证了上面的推理。



枚举是允许的,因为枚举类型的值可以用于ints。参见上面






在C ++ 11中如何改变?



C ++ 11放松限制在一定程度上。



C ++ 11 9.4.2静态数据成员

§3


如果静态数据成员是const字面类型,它在类定义中的声明可以指定 brace-or-equal-initializer 赋值语句 是一个常量表达式。可以在类定义中使用 constexpr specifier; 来声明文字类型的静态数据成员,如果是这样,则其声明应指定一个括号或初始值,其中每个赋值语句 initializer-clause 是一个常量表达式。 [注意:在这两种情况下,成员都可能出现在常量表达式中。 - end note]如果成员在程序中使用,并且命名空间范围定义不包含初始化程序,则成员仍然在命名空间范围中定义。


此外,C ++ 11 允许(§12.6.2.8)非静态数据成员在声明(在其类中)时被初始化。这将意味着很容易的用户语义。



请注意,这些功能尚未在最新的gcc 4.7中实现,因此您可能仍会收到编译错误。


Why I can't initialize non-const static member or static array in a class?

class A
{
    static const int a = 3;
    static int b = 3;
    static const int c[2] = { 1, 2 };
    static int d[2] = { 1, 2 };
};

int main()
{
    A a;

    return 0;
}

the compiler issues following errors:

g++ main.cpp
main.cpp:4:17: error: ISO C++ forbids in-class initialization of non-const static member ‘b’
main.cpp:5:26: error: a brace-enclosed initializer is not allowed here before ‘{’ token
main.cpp:5:33: error: invalid in-class initialization of static data member of non-integral type ‘const int [2]’
main.cpp:6:20: error: a brace-enclosed initializer is not allowed here before ‘{’ token
main.cpp:6:27: error: invalid in-class initialization of static data member of non-integral type ‘int [2]’

I have two questions:

  1. Why I can't initialize static data members in class?
  2. Why I can't initialize static arrays in class, even the const array?

解决方案

Why I can't initialize static data members in class?

The C++ standard allows only static constant integral or enumeration types to be initialized inside the class. This is the reason a is allowed to be initialized while others are not.

Reference:
C++03 9.4.2 Static data members
§4

If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a constant-initializer which shall be an integral constant expression (5.19). In that case, the member can appear in integral constant expressions. The member shall still be defined in a namespace scope if it is used in the program and the namespace scope definition shall not contain an initializer.

What are integral types?

C++03 3.9.1 Fundamental types
§7

Types bool, char, wchar_t, and the signed and unsigned integer types are collectively called integral types.43) A synonym for integral type is integer type.

Footnote:

43) Therefore, enumerations (7.2) are not integral; however, enumerations can be promoted to int, unsigned int, long, or unsigned long, as specified in 4.5.

Workaround:

You could use the enum trick to initialize an array inside your class definition.

class A 
{
    static const int a = 3;
    enum { arrsize = 2 };

    static const int c[arrsize] = { 1, 2 };

};

Why does the Standard does not allow this?

Bjarne explains this aptly here:

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. That rule would be broken if C++ allowed in-class definition of entities that needed to be stored in memory as objects.

Why are only static const integral types & enums allowed In-class Initialization?

The answer is hidden in Bjarne's quote read it closely,
"C++ requires that every object has a unique definition. That rule would be broken if C++ allowed in-class definition of entities that needed to be stored in memory as objects."

Note that only static const integers can be treated as compile time constants. The compiler knows that the integer value will not change anytime and hence it can apply its own magic and apply optimizations, the compiler simply inlines such class members i.e, they are not stored in memory anymore, As the need of being stored in memory is removed, it gives such variables the exception to rule mentioned by Bjarne.

It is noteworthy to note here that even if static const integral values can have In-Class Initialization, taking address of such variables is not allowed. One can take the address of a static member if (and only if) it has an out-of-class definition.This further validates the reasoning above.

enums are allowed this because values of an enumerated type can be used where ints are expected.see citation above


How does this change in C++11?

C++11 relaxes the restriction to certain extent.

C++11 9.4.2 Static data members
§3

If a static data member is of const literal type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both these cases, the member may appear in constant expressions. —end note ] The member shall still be defined in a namespace scope if it is used in the program and the namespace scope definition shall not contain an initializer.

Also, C++11 will allow(§12.6.2.8) a non-static data member to be initialized where it is declared(in its class). This will mean much easy user semantics.

Note that these features have not yet been implemented in latest gcc 4.7, So you might still get compilation errors.

这篇关于为什么我不能在类中初始化非const静态成员或静态数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆