web-dev-qa-db-ja.com

クラス定義での静的const整数メンバーの定義

私の理解では、整数型である限り、C++では静的constメンバーをクラス内で定義できます。

では、次のコードでリンカーエラーが発生するのはなぜですか?

#include <algorithm>
#include <iostream>

class test
{
public:
    static const int N = 10;
};

int main()
{
    std::cout << test::N << "\n";
    std::min(9, test::N);
}

私が得るエラーは次のとおりです:

test.cpp:(.text+0x130): undefined reference to `test::N'
collect2: ld returned 1 exit status

興味深いことに、std :: minの呼び出しをコメントアウトすると、コードはコンパイルされ、リンクが正常に行われます(test :: Nも前の行で参照されています)。

何が起こっているのか考えていますか?

私のコンパイラはLinux上のgcc 4.4です。

98
HighCommander4

私の理解では、整数型である限り、C++では静的constメンバーをクラス内で定義できます。

あなたは一種の正しいです。クラス宣言で静的const積分を初期化することはできますが、これは定義ではありません。

http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=/com.ibm.xlcpp8a.doc/language/ref/cplr038.htm

興味深いことに、std :: minの呼び出しをコメントアウトすると、コードはコンパイルされ、リンクが正常に行われます(test :: Nも前の行で参照されていますが)。

何が起こっているのか考えていますか?

std :: minは、const参照によってパラメーターを受け取ります。値で取得した場合、この問題は発生しませんが、参照が必要なため、定義も必要です。

ここに章/詩があります:

9.4.2/4 -staticデータメンバがconst整数型またはconst列挙型の場合、クラス定義でのその宣言は、 定数初期化子 整数定数式(5.19)でなければなりません。その場合、メンバーは整数定数式で表示できます。メンバーは、プログラムで使用されている場合、名前空間スコープで定義され、名前空間スコープ定義には 初期化子

可能な回避策については、Chuの回答を参照してください。

66
Edward Strange

Bjarne Stroustrupの例 彼のC++ FAQにある は、あなたが正しいことを示唆しており、住所を取得する場合にのみ定義が必要です。

class AE {
    // ...
public:
    static const int c6 = 7;
    static const int c7 = 31;
};

const int AE::c7;   // definition

int f()
{
    const int* p1 = &AE::c6;    // error: c6 not an lvalue
    const int* p2 = &AE::c7;    // ok
    // ...
}

彼は言い​​ます 「静的メンバーのアドレスを取得できるのは、クラス外の定義がある場合(およびその場合のみ)」。それはそれがそうでなければ動作することを示唆しています。たぶん、あなたのmin関数は舞台裏でアドレスを呼び出します。

45
HostileFork

これを行う別の方法は、とにかく整数型の場合、定数をクラスの列挙として定義することです。

class test
{
public:
    enum { N = 10 };
};
23
Stephen Chu

Intだけではありません。ただし、クラス宣言で値を定義することはできません。あなたが持っている場合:

class classname
{
    public:
       static int const N;
}

.hファイルには、次のものが必要です。

int const classname::N = 10;

.cppファイル内。

10
Amardeep AC9MF

問題を回避する別の方法を次に示します。

std::min(9, int(test::N));

(Crazy Eddieの答えは、問題が存在する理由を正しく説明していると思います。)

9
karadoc

C++ 11以降では、次を使用できます。

static constexpr int N = 10;

理論的には、.cppファイルで定数を定義する必要がありますが、Nのアドレスを取得しない限り、コンパイラの実装でエラーが発生することはほとんどありません;)。

5
Carlo Wood

C++では、クラス内で静的constメンバーを定義できます。

いいえ、3.1§2のコメント:

宣言は定義でない限り関数の本体を指定せずに関数を宣言し(8.4)、extern指定子(7.1.1)またはリンケージ仕様(7.5)を含み、初期化子もfunctionbody、クラス定義で静的データメンバーを宣言(9.4)、クラス名宣言(9.1)、opaque-enum-declaration(7.2)、またはtypedef宣言(7.1.3)、使用宣言(7.3.3)、または使用ディレクティブ(7.3.4)。

3
fredoverflow