[解決済み] コンストラクタでない静的メンバや静的配列をクラスで初期化できないのはなぜですか?
質問
コンストラクタでない
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]’
2つ質問があります。
-
なぜ私は初期化できないのですか?
static
のデータメンバを初期化できないのですか? -
を初期化できないのはなぜですか?
static
の配列も初期化できないのでしょうか?const
の配列は?
どのように解決するには?
初期化できない理由
static
のデータメンバを初期化できないのですか?
C++の標準では、クラス内部で初期化できるのは静的定数積分型または列挙型のみです。このため
a
が初期化され、他が初期化されないのはこのためです。
参考にしてください。
C++03 9.4.2 静的データメンバ
§4
静的データメンバがconst integral型またはconst enumeration型の場合、クラス定義におけるその宣言は、積分定数式でなければならない定数初期化子を指定することができます(5.19)。この場合,そのメンバは,積分定数式に現れることができる。そのメンバがプログラムで使用され,名前空間スコープ定義に初期化子が含まれてはならない場合,そのメンバは,依然として名前空間スコープで定義されなければならない。
積分型とは何ですか?
C++03 3.9.1 基本的な型
§7
bool型、char型、wchar_t型、符号付き整数型、符号なし整数型を総称して整数型と呼びます43)。整数型の同義語は整数型です。
脚注です。
<ブロッククオート43) したがって、列挙型(7.2)は積分型ではありません。しかし、列挙型は4.5で規定されているように、int、unsigned int、long、unsigned longに昇格させることが可能です。
回避策です。
この場合 enum のトリック を使って、クラス定義の中で配列を初期化することができます。
class A
{
static const int a = 3;
enum { arrsize = 2 };
static const int c[arrsize] = { 1, 2 };
};
なぜStandardはこれを許さないのですか?
Bjarneはこれを適切に説明しています。 ここで :
クラスは通常ヘッダーファイルで宣言され、ヘッダーファイルは通常多くの翻訳ユニットに含まれます。しかし、複雑なリンカー ルールを避けるため、C++ はすべてのオブジェクトが一意の定義を持つことを要求しています。C++ がオブジェクトとしてメモリに格納する必要のあるエンティティのクラス内定義を許可した場合、そのルールは破られることになります。
なぜ
static const
integral types & enums だけがクラス初期化を許されるのですか?
答えはBjarneの引用文に隠されています......よく読んでください。
C++ は、すべてのオブジェクトが一意の定義を持つことを要求しています。C++ がオブジェクトとしてメモリに格納する必要のあるエンティティのクラス内定義を許可した場合、そのルールは破られるでしょう。
のみであることに注意してください。
static const
のみがコンパイル時定数として扱われることに注意してください。コンパイラは整数の値がいつでも変化するわけではないことを知っているので、独自のマジックを適用して最適化を行うことができ、コンパイラは単にそのようなクラスメンバーをインライン化します。
ここで注目すべきなのは、たとえ
static const
がクラス内初期化を行えるとしても、そのような変数のアドレスの取得は許可されません。静的メンバがクラス外の定義を持っている場合(およびその場合のみ)、そのアドレスを取得することができます。
列挙型の値は int が期待される場所で使用できるため、列挙型は許可されています。 上記の引用を参照してください。
C++11 ではどのように変更されるのですか。
C++11 では、制限がある程度緩和されます。
C++11 9.4.2 静的データメンバ
§3
静的データメンバが const リテラル型である場合、クラス定義におけるその宣言では、静的データメンバを指定するために brace-or-equal-initializer を指定することができ、その中ですべての 初期化子節 であり 代入式 は定数式です。リテラル型の静的データメンバは、クラス定義で
constexpr specifier;
を指定することができ、その場合、その宣言は brace-or-equal-initializer を指定し,その中で,すべての 初期化子節 であり 代入式 は定数式です。[ 注意: これらの両方の場合において、メンバーは定数式に現れることがあります。-注を終了する ]。メンバがプログラムで使用される場合も、名前空間スコープで定義しなければならず、名前空間スコープの定義に初期化子を含んではならない。
また、C++11 では は は、非静的データメンバを宣言された場所(そのクラス内)で初期化することを許可します(§12.6.2.8)。これは、ユーザーのセマンティクスをより簡単にすることを意味します。
これらの機能は最新のgcc 4.7ではまだ実装されていないため、コンパイルエラーが発生する可能性があることに注意してください。
関連
-
[解決済み] エラーが発生する。ISO C++は型を持たない宣言を禁じています。
-
[解決済み】 != と =! の違いと例(C++の場合)
-
[解決済み】関数名の前に期待されるイニシャライザー
-
[解決済み】クラスのコンストラクタへの未定義参照、.cppファイルの修正も含む
-
[解決済み】デバッグアサーションに失敗しました
-
[解決済み] 変数サイズのオブジェクトが初期化されないことがある c++
-
[解決済み] Pythonで静的なクラス変数は可能ですか?
-
[解決済み] 静的クラスとシングルトンパターンの違い?
-
[解決済み] Static readonly」対「const」。
-
[解決済み】静的定数文字列(クラスメンバ)
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】構造体のベクター初期化について
-
[解決済み】C++ クラスヘッダが含まれているときに「不明な型」があるのはなぜですか?重複
-
[解決済み] クラスにデフォルトコンストラクタが存在しない。
-
[解決済み】c++でstd::vectorを返すための効率的な方法
-
[解決済み] 解決済み] `pthread_create' への未定義の参照 [重複] [重複
-
[解決済み】標準ライブラリにstd::endlに相当するタブはあるか?
-
[解決済み】Visual Studioのデバッガーエラー。プログラムを開始できません 指定されたファイルが見つかりません
-
[解決済み] 配列のベクトルを扱う正しい方法
-
[解決済み】変数やフィールドがvoid宣言されている
-
[解決済み] 変数サイズのオブジェクトが初期化されないことがある c++