2009-08-21 12 views
6
struct A { 
    static const int a = 5; 

    struct B { 
     static const int b = a; 
    }; 

}; 

int main() { 
    return A::B::b; 
} 

上記のコードがコンパイルされます。しかし、スコット・マイヤーズ(Scott Myers)のEffective C++の本(14ページ)を読んだら、 宣言に加えて、aの定義が必要です。 これは例外である理由を誰でも説明できますか?構造体/クラスのstatic const intを使用する

+1

コード_does_には 'a'の定義が含まれています。 –

+2

いいえ、定義は含まれていません。 –

+1

@Henk。あんまり。 'a'または 'b'のアドレスを関数に渡して、コンパイラが生成するメッセージを確認してください。 –

答えて

18

C++コンパイラでは、静的なconst整数(および整数のみ)は、宣言された場所で指定された値を持つことができます。これは、変数が本質的に必要ではなく、コード内にのみ存在するためです(通常はコンパイルされます)。

他の変数型(static const char *など)は、通常、宣言されている場所では定義できません。別の定義が必要です。

もう少し詳しく説明するには、グローバル変数にアクセスするには、通常、下位レベルのコードでアドレス参照を行う必要があります。しかし、あなたのグローバル変数は整数であり、これは典型的にはアドレスのサイズに近いサイズであり、コンパイラはそれが決して変わらないことを認識しているので、ポインタ抽象化を追加するのはどうしてですか?

+0

+1、素敵な答え。しかし、 'const'整数の場合はどうでしょうか?クラスでその価値を指定できますか? – Alcott

+0

"整数"ではなく、ただ定数式 – czxyl

18

本当にペダンティックなルールでは、あなたのコードではその静的整数の定義が必要です。 実際のルールと、すべてのコンパイラが実装しているのは、C++ 03の規則がどのように意図されているのかということです。いいえ、定義は必要ありません。

このような静的定数の規則は、値がすぐに読み取られるような状況でのみ整数が使用され、静的メンバーが定数式で使用できる場合に定義を省略できるようにしています。

リターンステートメントでは、メンバーの値がただちに読み込まれるため、静的定数メンバの唯一の使用であれば静的定数メンバの定義を省略できます。ただし、次のような状況では定義が必要です。

struct A { 
    static const int a = 5; 

    struct B { 
     static const int b = a; 
    }; 

}; 

int main() { 
    int *p = &A::B::b; 
} 

ここで値は読み取られませんが、代わりにアドレスが使用されます。したがって、C++ 03標準の目的は、いくつかの実装ファイルで次のようなメンバの定義を提供する必要があるということです。

const int A::B::b; 

注C++ 03標準に現れる実際ルールは、変数が使用される場合にのみ定数式は、を要求される定義が必要とされないと言うこと。しかし、この規則は厳格に適用されれば、厳格すぎる。配列次元のような状況の定義を省略することができますが、return文のような場合には定義が必要になります。対応する欠陥報告はhereです。

C++ 0xの言葉は、その欠陥報告の解決を含むように更新され、あなたのコードを書かれたものとして許可します。一般的に

+0

Walt Wが間違っているということは、「C++コンパイラでは静的なconst整数(および整数のみ)を宣言された場所に定義できます」という意味ですか?私は彼のように思った "静的な定数int a = 5;"ステートメントは宣言と定義の両方でした。私が正しく理解しているならば、定義なしの宣言にすぎず、A :: aは非常に特殊なケースでのみ使用できます。私は最後の言葉でintesrested ... – neuro

+0

はい、彼も間違っています。それは宣言にすぎません。定義ではありません。値を直ちに読み取らない場合に参照する場合は、定義が必要です。あなたはあなたのコメントでそれを持っているようです。 –

+0

もっと良いですか?私はそれは "定義"の技術的な使用ではなかったと思う –

0

、ほとんどの(最近の)C++コンパイラは、静的定数は、あなただけの幸運、おそらくない

をint型許します。 gcc 2.0のような古いコンパイラを試してみてください。そうすれば、あまりにもきれいなエラーメッセージであなたを激しく罰するでしょう。

1

あなたは静的constsを「定義」することなく、三元オペランドをしようとした場合しかし、あなたはGCC 4倍速でのリンカエラーを取得:

だから、

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=13795

int k = A::CONSTVAL;ような構築物は、現在の標準では違法であるが、彼らはサポートされています。しかし、三項オペランドはそうではありません。あなたが私のドリフトを得るならば、いくつかの演算子は他のものよりも同等です。

「怠惰な」ルールのための多くのこと。私はあなたが驚きをしたくない場合は、標準に準拠したコードを書くことをお勧めします。