web-dev-qa-db-ja.com

静的constデータメンバーの宣言と定義に関する混乱

Scott Meyersは、Effective Modern C++、Item 30 page 210に次のように書いています。

積分を定義する必要はありませんstatic constクラスのデータメンバー。宣言だけで十分です、

次に、サンプルコードは

class Widget {
  public:
    static const std::size_t MinVals = 28; // MinVals' declaration;
    ...
};
...                                        // no defn. for MinVals
std::vector<int> widgetData;
widgetData.reserve(Widget::MinVals);       // use of MinVals

static const std::size_t MinVals = 28;は宣言ですまた、MinVals、しかしコメントはそれが単なる宣言であると主張しているようです; 2番目のコメントは、実際には定義がないと主張しています。コードの後のテキスト、確かに

MinValsには定義がありません。

これはstatic const std::size_t MinVals = 28;は定義ではないので、少し混乱しています。

cppreference はあまり役に立ちません(私の太字斜体):

整数型または列挙型のstaticデータメンバーがdeclaredconstvolatileではなく)、すべての式が定数式であるイニシャライザで初期化できます。

struct X
{
    const static int n = 1;
    const static int m{2}; // since C++11
    const static int k;
};
const int X::k = 3;

しかし、クラスの最初の2行は私に定義を見ています。

同じことがcppreferenceの次の例にも当てはまります。

struct X {
    static const int n = 1;
    static constexpr int m = 4;
};
const int *p = &X::n, *q = &X::m; // X::n and X::m are odr-used
const int X::n;             // … so a definition is necessary
constexpr int X::m;         // … (except for X::m in C++17)

どこで言ったかstatic const int n = 1;は定義ですが、最後から2番目のコメントに基づいて定義されています。

これを見ると Draft Standard を見ると、例が灰色の領域にあるように見えます。次のような行のexplicit言及はありませんが、

    static const std::size_t MinVals = 28;

非常に似ている与えられた例があります

6.1宣言と定義
...
2宣言は、以下の場合を除き、定義です
...
2.3 —クラス定義で非インラインの静的データメンバーを宣言します
...
例:以下の1つを除くすべてが定義です。

int a; //を定義します
extern const int c = 1; // cを定義します
...

2番目の例は、コードにcloseですが、extern修飾子を持つことに大きな違いがあります。また、上記では、宣言は(デフォルトでは)definitionでもあると明記されています。私は(Language-Lawyerではありませんが)これらの条件のいずれも満たされていない場合は正確にと言うので、宣言はまた、定義。

注:リンクされたドキュメントはdraft標準のみです。最初のページの下部にある「免責事項」を必ずお読みください。

3
Adrian Mole

From The Standard Chapter "12.2.3.2 Static data members":

プログラムでメンバーがodrで使用され、名前空間スコープ定義に初期化子が含まれていない場合、メンバーは引き続き名前空間スコープで定義されます。

それを使用することで定義されます。

0
Dragan