c++ - 为什么我不能在类中初始化非常量静态成员或静态数组?

标签 c++ static constants

为什么我不能在一个类中初始化非 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++ 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]’

我有两个问题:

  1. 为什么我不能初始化类中的static数据成员?
  2. 为什么我不能在类中初始化static数组,甚至是const数组?

最佳答案

为什么我不能初始化类中的static数据成员?

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

引用:
C++03 9.4.2 静态数据成员
§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.

什么是整数类型?

C++03 3.9.1 基本类型
§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.

脚注:

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.

解决方法:

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

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

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

};

为什么标准不允许这样做?

Bjarne 恰本地解释了这一点 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.

为什么只允许 static const 整数类型和枚举类内初始化?

答案隐藏在 Bjarne 的名言中仔细阅读,
“C++ 要求每个对象都有一个唯一的定义。如果 C++ 允许在类内定义需要作为对象存储在内存中的实体,则该规则将被打破。”

请注意,只有 static const 整数可以被视为编译时常量。编译器知道整数值不会随时改变,因此它可以应用自己的魔法并应用优化,编译器只是内联此类成员,即它们不再存储在内存中,因为不需要存储在内存中,它为这些变量提供了 Bjarne 提到的规则的异常(exception)。

这里需要注意的是,即使 static const 整数值可以进行类内初始化,也不允许取此类变量的地址。当(且仅当)静态成员具有类外定义时,可以获取静态成员的地址。这进一步验证了上述推理。

枚举是允许的,因为枚举类型的值可以用在需要整数的地方。参见上面的引用


这在 C++11 中有何变化?

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

C++11 9.4.2 静态数据成员
§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.

此外,C++11 允许(§12.6.2.8)一个非静态数据成员在它被声明的地方(在其类中)进行初始化。这将意味着更简单的用户语义。

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

关于c++ - 为什么我不能在类中初始化非常量静态成员或静态数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9656941/

相关文章:

c++ - 从常量函数返回引用

c++ - if 子句中的条件赋值

c++ - 来自异步服务器的套接字写入 - 但不读取

C - (malloc、calloc 或静态)从函数返回的二维字符数组

c++ - 静态和非静态递归成员之间的区别

c++ - const T * search ( const T &) 返回无效

c++ - c++\msdn 中的这个 "CONSTANT>>1"是什么

c++ - C++ MS Visual Studio错误 “referenced in function public: void __thiscall …”

c++ - EnumChildWindows 和 lambda

c++ - 我们可以使用 `LoadLibrary ` 让我们的应用程序使用 Visual Studio 2010 和静态运行时编译吗?