4

重複の可能性
クラスに非整数 static const メンバーを含めることができないのはなぜですか?

struct Example
{
    static const int One = 1000; // Legal
    static const short Two = 2000; // Illegal
    static const float Three = 2000.0f; // Illegal
    static const double Four = 3000.0; // Illegal
    static const string Five = "Hello"; // Illegal
};

#2、#3、#4、#5 が違法である理由はありますか?

#5の理由はわかっていると思います:コンパイラは「実際の」文字列オブジェクトを必要とし(組み込み型ではないため)、無意識のうちに であるかのように置き換えることはできFiveませ"Hello"#define Five "Hello"。しかし、その場合、コンパイラは .obj ファイルにヒントを残して、リンカにstring Fiveどこかのインスタンスを 1 つ自動的に作成するように指示できませんか?

#3 と #4、特に #2 については (笑)... 考えられる理由がまったくわかりません! int と同様に、float と double は組み込み型です。そして short は、(おそらく) より短い整数です。


編集: Visual Studio 2008 を使用してコンパイルしています。この場合、すべてのコンパイラが同じように動作すると思いましたが、明らかに g++ は問題なくコンパイルされます (#5 を除く)。そのスニペットに対してVSが与えるエラーは次のとおりです。

    エラー C2864: 'Example::Two': クラス内で初期化できるのは static const 整数データ メンバーのみです
    エラー C2864: 'Example::Three': クラス内で初期化できるのは static const 整数データ メンバーのみです
    エラー C2864: 'Example::Four': クラス内で初期化できるのは static const 整数データ メンバーのみです
    エラー C2864: 'Example::Five': クラス内で初期化できるのは static const 整数データ メンバーのみです
4

8 に答える 8

7

intとshortは合法であり、コンパイラがそれらを許可しない場合、コンパイラは無効になります。

9.4.2 / 4:...静的データメンバーがconst整数型またはconst列挙型の場合、クラス定義での宣言 により、整数定数式となる定数初期化子を指定できます。

整数型のように、floatとdoubleがC ++標準で定数として特別に扱われない理由は、C ++標準では、floatとdoubleの算術演算が微妙に異なる可能性があることに注意しているためです。コードを実行するマシン上にあるよりも、マシンをコンパイルします。コンパイラが(a + b)のような定数式を評価するには、ランタイムが取得するのと同じ答えを取得する必要があります。

これはintの問題ではありません。整数演算が異なる場合は、比較的安価にエミュレートできます。ただし、コンパイラがターゲットデバイス上の浮動小数点ハードウェアをエミュレートするのは非常に難しい場合があります。チップのバージョンが異なり、コンパイラがどのコードで実行されるかわからない場合は、不可能な場合もあります。そして、それはあなたがIEEE丸めモードをいじり始める前ですらあります。そのため、標準ではそれを要求することを避け、コンパイル時の評価が実行時の評価といつどのように異なるかを定義する必要がなくなりました。

ブライアンが言及しているように、C++0xはこれに。で対処しconstexprます。私が本来の動機について正しければ、おそらく10年は、このようなものを特定する際の困難を乗り越えるのに十分な長さでした。

于 2009-12-15T13:11:05.983 に答える
4

Example::Oneとは両方ともExample::Twoあなたのためにコンパイルする必要があります、そしてそれらはあなたが述べたのと同じ環境(VS2008)で実際に私のためにコンパイルします。

Example::Three私は信じていませんExample::Four。標準のC++でコンパイルする必要がありますが、それを可能にするgcc拡張機能があると思います。 Example::Fiveコンパイルしないでください。

struct宣言の後で、通常はソースファイルで次のように初期化できます。

const float Example::Three = 2000.0f;
const double Example::Four = 3000.0;
const string Example::Five = "Hello";

Example::Threeこれはそれを行うための最も移植性の高い方法であり、コンパイラーで定義とExample::Four宣言を許可している場合でも、これを行うことをお勧めします。

別のオプションは、同じタイプの静的関数から値を返すことです。

struct Example
{
    //...
    static double Four() { return  = 3000.0; }
    //...
};

この回答では、考えられる理由についても説明しています。
この回答では、今後のC++標準がconstexprを介してどのように役立つかについて説明します。

于 2009-12-15T12:54:38.990 に答える
1

C++98 では、クラス内で初期化できるのは整数型の static const メンバーのみであり、初期化子は定数式でなければなりません。これらの制限により、コンパイル時に初期化を行うことができます。

クラス内メンバー初期化子を参照してください。

§9.4.2 静的データ メンバー

静的データ メンバーが const 整数型または const 列挙型の場合、クラス定義でのその宣言は、整数定数式 (5.19) である定数初期化子を指定できます。その場合、メンバーは整数定数式に表示できます。メンバーがプログラムで使用され、名前空間スコープの定義に初期化子が含まれていない場合、メンバーは名前空間スコープで定義されます。

于 2009-12-15T12:58:53.053 に答える
1

#1と2は規格に準拠しています。残念ながら、一部のコンパイラは準拠していません。そのため、たとえば、Boost の設計者は、BOOST_STATIC_CONSTANTポータブル ライブラリを生成するような面倒なマクロを導入する必要がありました。.cpp ファイルで定数を定義したくない場合、ポータブルな回避策は .cpp ファイルを使用することenumです。ただし、明らかにその場合、型についての保証はなく、float を使用することはできません。

于 2009-12-15T13:04:37.460 に答える
0

浮動小数点初期化子に関して、C++98 仕様には次のように書かれています (5.19):

浮動リテラルは、整数型または列挙型にキャストされている場合にのみ表示できます。

于 2009-12-15T13:22:07.910 に答える
0

VS2008 では、次のエラーが発生します。

1>.\Weapon Identification SystemDlg.cpp(223) : error C2864: 'Example::Three' : only static const integral data members can be initialized within a class
1>.\Weapon Identification SystemDlg.cpp(224) : error C2864: 'Example::Four' : only static const integral data members can be initialized within a class
1>.\Weapon Identification SystemDlg.cpp(225) : error C2864: 'Example::Five' : only static const integral data members can be initialized within a class

それはひどいですが、コンパイラも拒否した場合は、それを行う必要はないと思います...これが仕様の問題であることを認識していませんが、誰かが私を修正すると確信しています...

于 2009-12-15T12:59:17.207 に答える
0

他の人が発見したように、C++ 標準では、静的な const メンバーを浮動小数点値で初期化することを禁止しています。

少なくとも私が理解している限りでは、これにはかなり単純な理由があります。実装が浮動小数点の精度を動的に調整できるようにする必要があるという感覚 (少なくとも部分的には正当化されます) があるため、特定の浮動小数点から生成される/生成される正確な浮動小数点値を実装が認識するのは実行時までではない可能性があります。リテラル。実際、実行中にこれが変更される可能性さえあります。

この機能は実際のハードウェアに存在します。たとえば、Intel x86 の浮動小数点制御レジスタには、浮動小数点計算の精度を制御するビットがいくつかあります。デフォルトでは、計算は 80 ビットの長さの double 型で行われ、要求に応じて 64 ビットの double や 32 ビットの float などに丸められるだけです。レジスタ内のこれらのビットは実行中に変更できるため、(たとえば) ある場所の "1.23" は変数を 1 つの値に初期化でき、プログラムの別の部分 (精度が調整された後) の "1.23" になる可能性があります。 (わずかに)異なる値で。

少なくとも私の知る限り、少なくともほとんどの典型的なマシンでは、これは依然として理論的な可能性です。Intel ハードウェアでは FP の精度を動的に調整できますが、FP リテラルを変換するときにそのような調整を考慮に入れようとするコンパイラ (Intel のコンパイラでさえ) は知りません (ただし、Intel のコンパイラは少なくとも 80 ビット長のダブルタイプ)。

于 2009-12-15T15:08:51.157 に答える
0

他の人が指摘したように、コンパイラが壊れている場合があります。しかし、「標準がそう言っている」以外に、浮動小数点型に許可されていない理由を本当に理解したことがありません。適切な技術的理由はないようです。

于 2009-12-15T22:56:30.270 に答える