なぜクラス定義に初期化子がありますか? const
とconstexpr
静的データメンバのための2つの例外に関する
:
[class.static.data]/3
は[注:これらの両方の場合において、メンバーは、定数式で表示されること。 - 終了ノート]
I.e.初期化子を使用して、定数式で使用することができます。
struct s
{
static std::size_t const len = 10;
int arr[len];
};
std::size_t const s::len;
len
は、クラス定義で初期化されていない場合は、コンパイラが簡単にarr
の長さを定義するために次の行にその値を知ることができませんでした。
一つは、クラス定義で、const
非非constexpr
静的データメンバのための初期化子を許可について議論ができ、これは、初期化順序を妨げる可能性:
[basic.start.init]/2
明示的に特殊化されたクラステンプレートの静的データメンバーの定義は、順序付けられた初期化を持っています。他のクラステンプレート静的データメンバー(すなわち、暗黙的にまたは明示的にインスタンス化された特殊化)は、順序付けされていない初期化を有する。 静的記憶期間を持つ他の非ローカル変数は、順序付けられた初期化を持っています。
つまり、イニシャライザを含む定義の順序が重要です。非ローカルオブジェクトの(動的な)初期化の順序は、翻訳単位内でのみ定義されます。これは、非const
、非constexpr
静的データメンバーの初期化子を含む定義がなければならないもう一つの理由です。
この追加定義のポイントは何ですか。
これは既にIMOのコメントで回答されています。 ODRを追加することもできます。つまり、外部リンケージを持つ名前として、静的データメンバーは(ODRを使用している場合は)1つの翻訳単位で定義する必要があります。この翻訳単位を選択するのはプログラマの責任です。
出典
2013-05-04 12:26:19
dyp
重要な点は、変数をodr-usedにするかどうかです。そうでないかぎり、変数を参照するたびに*値*を貼り付けるだけで十分であるため、実際に変数を定義する必要はありません。 –
これは**余分な**定義ではありません。それは定義です。クラス本体の内部に**宣言**があります。 –
異なる翻訳単位(= cppファイル)から静的データメンバーにアクセスしたい場合は、すべての翻訳単位が参照する場所、つまり静的メンバーが定義されている単一の翻訳単位を定義する必要があります。これは、(グローバル)extern変数と同じことです。 – dyp