C++ 为什么我不能在类中初始化非常量静态成员或静态数组?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9656941/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why can't I initialize non-const static member or static array in class?
提问by Yishu Fang
Why can't I initialize non-const static
member or static
array in a class?
为什么我不能在类中初始化非常量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;
}
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:
我有两个问题:
- Why can't I initialize
static
data members in class? - Why can't I initialize
static
arrays in class, even theconst
array?
- 为什么我不能
static
在类中初始化数据成员? - 为什么我不能
static
在类中初始化数组,甚至是const
数组?
回答by Alok Save
Why I can't initialize static
data members in class?
为什么我不能static
在类中初始化数据成员?
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.
C++ 标准只允许在类内部初始化静态常量整数或枚举类型。这就是a
允许初始化而其他不允许的原因。
Reference:
C++03 9.4.2 Static data members
§4
参考:
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.
如果静态数据成员是 const 整型或 const 枚举类型,则它在类定义中的声明可以指定一个常量初始化器,它应该是一个整型常量表达式 (5.19)。在这种情况下,成员可以出现在整数常量表达式中。如果在程序中使用该成员,则该成员仍应在名称空间范围内定义,并且名称空间范围定义不应包含初始化程序。
What are integral types?
什么是整数类型?
C++03 3.9.1 Fundamental types
§7
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.
类型 bool、char、wchar_t 以及有符号和无符号整数类型统称为整数类型。43) 整数类型的同义词是整数类型。
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.
43)因此,枚举 (7.2) 不是整数;但是,枚举可以提升为 int、unsigned int、long 或 unsigned long,如 4.5 中所指定。
Workaround:
解决方法:
You could use the enum trickto 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.
类通常在头文件中声明,而头文件通常包含在许多翻译单元中。但是,为了避免复杂的链接器规则,C++ 要求每个对象都有唯一的定义。如果 C++ 允许需要作为对象存储在内存中的实体的类内定义,那么这条规则就会被打破。
Why are only static const
integral types & enums allowed In-class Initialization?
为什么只static const
允许整数类型和枚举进行类内初始化?
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."
答案隐藏在 Bjarne 的引用中仔细阅读,
“C++ 要求每个对象都有一个唯一的定义。如果 C++ 允许将需要作为对象存储在内存中的实体的类内定义,那么这条规则就会被打破。”
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.
请注意,只有static const
整数才能被视为编译时常量。编译器知道整数值不会在任何时候改变,因此它可以应用自己的魔法并应用优化,编译器简单地内联这些类成员,即它们不再存储在内存中,因为不需要存储在内存中,它使这些变量成为 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.
这里值得注意的是,即使static const
整数值可以进行类内初始化,也不允许对此类变量取地址。如果(且仅当)静态成员具有类外定义,则可以获取静态成员的地址。这进一步验证了上述推理。
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 中有何变化?
C++11 relaxes the restriction to certain extent.
C++11在一定程度上放宽了限制。
C++11 9.4.2 Static data members
§3
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-initializerin which every initializer-clausethat is an assignment-expressionis 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-initializerin which every initializer-clausethat is an assignment-expressionis 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.
如果静态数据成员是 const 文字类型,则它在类定义中的声明可以指定一个大括号或等号初始化器,其中每个作为赋值表达式的初始化器子句都是一个常量表达式。文字类型的静态数据成员可以在类定义中声明,如果是,它的声明应指定一个大括号或等号初始化器,其中每个初始化器子句都是赋值表达式
constexpr specifier;
是一个常量表达式。[ 注意:在这两种情况下,成员都可能出现在常量表达式中。—end note ] 如果在程序中使用该成员,则该成员仍应在名称空间范围内定义,并且名称空间范围定义不应包含初始化程序。
Also, C++11 willallow(§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.
此外,C++11将允许(第 12.6.2.8 节)一个非静态数据成员在它被声明的地方(在它的类中)被初始化。这将意味着更容易的用户语义。
Note that these features have not yet been implemented in latest gcc 4.7, So you might still get compilation errors.
请注意,这些功能尚未在最新的 gcc 4.7 中实现,因此您可能仍然会遇到编译错误。
回答by not-a-user
This seems a relict from the old days of simple linkers. You can use static variables in static methods as workaround:
这似乎是过去简单链接器的遗物。您可以在静态方法中使用静态变量作为解决方法:
// header.hxx
#include <vector>
class Class {
public:
static std::vector<int> & replacement_for_initialized_static_non_const_variable() {
static std::vector<int> Static {42, 0, 1900, 1998};
return Static;
}
};
int compilation_unit_a();
and
和
// compilation_unit_a.cxx
#include "header.hxx"
int compilation_unit_a() {
return Class::replacement_for_initialized_static_non_const_variable()[1]++;
}
and
和
// main.cxx
#include "header.hxx"
#include <iostream>
int main() {
std::cout
<< compilation_unit_a()
<< Class::replacement_for_initialized_static_non_const_variable()[1]++
<< compilation_unit_a()
<< Class::replacement_for_initialized_static_non_const_variable()[1]++
<< std::endl;
}
build:
建造:
g++ -std=gnu++0x -save-temps=obj -c compilation_unit_a.cxx
g++ -std=gnu++0x -o main main.cxx compilation_unit_a.o
run:
跑:
./main
The fact that this works (consistently, even if the class definition is included in different compilation units), shows that the linker today (gcc 4.9.2) is actually smart enough.
这有效的事实(始终如一,即使类定义包含在不同的编译单元中)表明今天的链接器(gcc 4.9.2)实际上已经足够聪明了。
Funny: Prints 0123
on arm and 3210
on x86.
有趣:0123
在手臂和3210
x86 上打印。
回答by user541686
I think it's to prevent you from mixing declarations and definitions. (Think about the problems that could occur if you include the file in multiple places.)
我认为这是为了防止您混淆声明和定义。(想想如果在多个地方包含文件可能会出现的问题。)
回答by user541686
static variables are specific to a class . Constructors initialize attributes ESPECIALY for an instance.
静态变量特定于类。构造函数特别为实例初始化属性。