211

次のコードがコンパイルされない理由を誰か説明できますか? 少なくとも g++ 4.2.4 では。

さらに興味深いことに、MEMBER を int にキャストするとコンパイルされるのはなぜですか?

#include <vector>

class Foo {  
public:  
    static const int MEMBER = 1;  
};

int main(){  
    vector<int> v;  
    v.push_back( Foo::MEMBER );       // undefined reference to `Foo::MEMBER'
    v.push_back( (int) Foo::MEMBER ); // OK  
    return 0;
}
4

9 に答える 9

203

実際に static メンバーをどこか (クラス定義の後) に定義する必要があります。これを試して:

class Foo { /* ... */ };

const int Foo::MEMBER;

int main() { /* ... */ }

これにより、未定義の参照が取り除かれます。

于 2008-11-07T17:57:35.213 に答える
78

この問題は、新しい C++ 機能とあなたがしようとしていることの興味深い衝突が原因で発生します。push_backまず、署名を見てみましょう。

void push_back(const T&)

タイプ のオブジェクトへの参照が必要Tです。初期化の古いシステムでは、そのようなメンバーが存在します。たとえば、次のコードは正常にコンパイルされます。

#include <vector>

class Foo {
public:
    static const int MEMBER;
};

const int Foo::MEMBER = 1; 

int main(){
    std::vector<int> v;
    v.push_back( Foo::MEMBER );       // undefined reference to `Foo::MEMBER'
    v.push_back( (int) Foo::MEMBER ); // OK  
    return 0;
}

これは、その値が格納されている実際のオブジェクトがどこかにあるためです。ただし、静的 const メンバーを指定する新しい方法に切り替えると、上記のようにFoo::MEMBERオブジェクトではなくなります。これは定数で、次のようなものです。

#define MEMBER 1

しかし、プリプロセッサ マクロの頭痛の種はありません (そして型安全性も備えています)。これは、参照を予期しているベクトルが参照を取得できないことを意味します。

于 2008-11-07T18:00:46.907 に答える
62

C++ 標準では、何らかの理由で定義が必要な場合、静的 const メンバーの定義が必要です。

たとえば、アドレスが使用されている場合は、定義が必要です。 push_backconst 参照によってパラメーターを取得するため、厳密にはコンパイラーはメンバーのアドレスを必要とし、名前空間でそれを定義する必要があります。

定数を明示的にキャストすると、一時的なものが作成され、参照にバインドされるのはこの一時的なものです (標準の特別な規則の下で)。

これは非常に興味深いケースであり、定数メンバーに対して同じ動作をするように std を変更するように問題を提起する価値があると実際に思います!

ただし、奇妙な方法で、これは単項「+」演算子の正当な使用法と見なすことができます。基本的に、の結果はunary +右辺値であるため、右辺値を const 参照にバインドするための規則が適用され、静的 const メンバーのアドレスは使用しません。

v.push_back( +Foo::MEMBER );
于 2008-11-07T18:03:49.927 に答える
10

ああああ

class Aaa {

protected:

    static Aaa *defaultAaa;

};

Aaa.cpp

// You must define an actual variable in your program for the static members of the classes

static Aaa *Aaa::defaultAaa;
于 2012-12-04T08:32:36.703 に答える
1

C++11 では、上記は次のような基本型で可能です。

class Foo {
public:  
  static constexpr int MEMBER = 1;  
};

このconstexpr部分は、静的変数ではなく静的を作成します。これは、非常に単純なインライン メソッド定義のように動作します。ただし、このアプローチは、テンプレート クラス内の C 文字列 constexprs では少し不安定であることがわかりました。

于 2016-06-20T07:12:30.527 に答える
1

キャストが機能する理由はわかりませんが、Foo::MEMBER は初めて Foo がロードされるまで割り当てられません。また、決してロードしないため、割り当てられません。どこかに Foo への参照があれば、おそらくうまくいくでしょう。

于 2008-11-07T18:01:53.783 に答える
0

2 番目の質問について: push_ref はパラメーターとして参照を受け取り、クラス/構造体の static const メンバーへの参照を持つことはできません。static_cast を呼び出すと、一時変数が作成されます。そして、このオブジェクトへの参照を渡すことができ、すべてがうまく機能します。

または、少なくともこれを解決した私の同僚はそう言いました。

于 2014-07-18T12:44:30.173 に答える