C ++が匿名の構造体を許可しないのはなぜですか?


92

一部のC ++コンパイラーは、匿名の共用体と構造体を標準C ++の拡張として許可します。これは、時々非常に役立つ、ちょっとした構文上の砂糖です。

これが標準の一部にならないようにする根拠は何ですか?技術的な障害はありますか?哲学的なもの?それともそれを正当化する必要性が十分ではないのですか?

これが私が話していることのサンプルです:

struct vector3 {
  union {
    struct {
      float x;
      float y;
      float z;
    };
    float v[3];
  };
};

私のコンパイラはこれを受け入れますが、「無名の構造体/共用体」はC ++に対する非標準の拡張であることを警告しています


3
明らかに、あなたが何を意味するのかについていくつかの混乱があります。コンパイラー拡張機能のためにコンパイルのみを行うコードの例を提供していただけませんか?
ロブ・ケネディ

74
似ているように聞こえますが、大きく異なる2つの概念があります。名前のない構造体匿名の構造体です。1つ目は、C ++がサポートするこれですstruct { int i; } a; a.i = 0;(タイプには名前がありません)。2番目は、C ++がサポートしていないこれですstruct { int i; }; i = 0;(タイプには名前がなく、周囲のスコープにエスケープします)。ただし、C ++は、名前のない共用体と匿名の共用体の両方をサポートしています。
Johannes Schaub-litb

これは、かなり興味深いVMMLibベクトルライブラリのように見えます。問題は、ユニオンに名前のない構造体が含まれていることですが、私にはわかりません。
greyfade 2010

1
FWIWこれは「無名」ではなく「匿名」であり、労働組合 litbが言うようにサポートされています。stackoverflow.com/q/14248044/560648
オービットの軽量レース、

1
@AdrianMcCarthy:それは問題ありません(FSVOは「問題ありません」;厄介なコンパイラーは不可解です)が、正確に「名前なし」は無関係の標準的な概念です。
オービットのライトネスレース2013年

回答:


50

他の人が指摘したように、匿名の共用体は標準C ++で許可されていますが、匿名の構造体は許可されていません。

これは、Cが匿名の共用体をサポートし、匿名の構造体*をサポートしていないためです。したがって、C ++は互換性のために前者をサポートしますが、互換性のために必要ではないため、後者はサポートしません。

さらに、C ++では匿名の構造体はあまり使用されません。次のいずれかで参照できる3つのfloatを含む構造体を作成するための使用例.v[i]、または.x.y、と.z、私はC ++での未定義の動作に結果を信じています。C ++では、ユニオンの1つのメンバーに書き込み、たとえば.v[1]別のメンバーから読み取ることはできません.y。これを行うコードは珍しくありませんが、実際には明確に定義されていません。

ユーザー定義型用のC ++の機能は、代替ソリューションを提供します。例えば:

struct vector3 {
  float v[3];
  float &operator[] (int i) { return v[i]; }
  float &x() { return v[0]; }
  float &y() { return v[1]; }
  float &z() { return v[2]; }
};

* C11はどうやら匿名の構造体を追加しているため、C ++の将来のリビジョンで追加される可能性があります。


2
+1:私の例は、C ++での未定義の動作に依存しています-質問を書いたときに気付かなかったものです。
エイドリアンマッカーシー、

2
「C ++では、共用体の1つのメンバーに書き込み、別のメンバーから読み取ることはできません」- 上記のメンバーが標準レイアウトオブジェクトであり、独自のメンバーの共通の初期シーケンスを共有していない限り、再書き込み/読み込み彼らの言った共通の初期シーケンス内のメンバーを。それ許可されます(つまり、定義されます)。
underscore_d

5
@underscore_d:はい、タイプが共通の初期シーケンスを持つ標準レイアウトの場合。ただし、C ++の「共通の初期シーケンス」の規則では、共通の初期シーケンスはstructの間にのみ存在できると規定されているため、構造体はこの方法で配列とエイリアスすることはできません。配列は言及されていないため、このようにエイリアスすることはできません。
Nicol Bolas

@NicolBolasああ、はは-私を信じて-私は何度も配列や他のプリミティブがこの手当に含まれることを望んでいました!しかし、私はそれについて考えられる実際的な制限についてはあまり考えていなかったので、おそらくそれは現在のように単純ではありません。私のコメントは、より一般的だったかもしれないが、としましたが中にいることを追加するためのおかげので、私はこの中に含まれた配列を考えていることを省略することにより、暗示危険にさらした。
underscore_d

「この理由は、Cは匿名の共用体をサポートするが匿名の構造体はサポートしないためです」-いいえ。脚注は、ここでC99以前について話していたことを明らかにしています。「匿名組合」という用語は、C99標準のどこにも登場しません。GCCは、診断で(-std = c99 -pedanticオプションを使用して)「ISO C99は名前のない構造体/共用体をサポートしていない」と主張しています。標準では、名前のないビットフィールド以外の名前のないメンバーについては何も言及されていません。struct-declarationsが宣言であるかどうかは完全にはわかりませんが、そうである場合、匿名共用体は6.7p2による制約違反であり、せいぜい未定義です。

21

私は言うでしょう、あなたはvector3単にunion

union vector3 {
  struct { float x, y, z; } ;
  float v[3] ;
} ;

確かに、匿名構造 MSVC拡張でした。しかし、ISO C11は今それを許可し、gccはそれを許可し、Appleのllvmコンパイラも許可します

なぜC ++ 11ではなくC11なのですか?確かではありませんが、ほとんどの場合(gcc ++、MSVC ++、およびAppleのC ++コンパイラ)C ++コンパイラがそれらをサポートしています。


1
更新された情報の+1。私が外部構造体を持っている理由は、「実際のコード」にもメソッドがあったからです。
エイドリアンマッカーシー、

ユニオンで実行できない唯一のことは、静的データメンバーを持つか、継承を使用することです。
bobobobo 2012年

2
ありがとう。ユニオンを構造体やクラスのように使用することはできません。
エイドリアンマッカーシー、

Sun studioはデフォルトでC ++ 11より前の匿名構造体をサポートしていなかったのは知っています。クロスプラットフォームコードを記述していて、コンパイラがC + 11にアップグレードされていない場合は、匿名の構造体を使用しないでください。
irsis

6

よく分からない。C ++仕様のセクション9.5、2節:

フォームの結合

union { member-specification } ;

匿名組合と呼ばれます。名前のないタイプの名前のないオブジェクトを定義します。

次のようなこともできます:

void foo()
{
  typedef
  struct { // unnamed, is that what you mean by anonymous?
    int a;
    char b;
  } MyStructType; // this is more of a "C" style, but valid C++ nonetheless

  struct { // an anonymous struct, not even typedef'd
    double x;
    double y;
  } point = { 1.0, 3.4 };
}

必ずしも非常に役立つとは限りませんが、厄介なマクロ定義で役立つこともあります。


11
-1は、匿名の構造体を定義していると言っているためです。質問に関する上記のコメントを参照してください-匿名ではなく、名前のない構造体を定義しています。
Johannes Schaub-litb

1

組合は匿名にすることができます。標準、9.5パラグラフ2を参照してください。

匿名の構造体またはクラスが充実していると考えている目的は何ですか?なぜ何かが規格にないのかを推測する前に、なぜそれがそうあるべきなのかについて考えたいのですが、匿名の構造体の使用法はわかりません。


1

編集、コメント、およびこのMSDNの記事「匿名の構造」に基づいて、私は推測を危険にさらします-カプセル化の概念にはあまり適合しません。クラスのメンバーが1つのメンバーを追加するだけで、クラスの名前空間を混乱させることはないと思います。さらに、匿名の構造を変更すると、許可なくクラスに影響を与える可能性があります。


1
匿名の構造体/共用体の作成方法(マクロ以外は非表示にできない特別なインライン構文)のため、使用している一部のメンバーが匿名のメンバーであることに驚くことはありません。だから私はこの推論が意味をなさないと思います。実際の理由は、匿名の共用体 C ++でサポートされていることです。これは、Cの互換性のためだけです。Cは(C11まで)匿名構造体をサポートしていないため、C ++もサポートしていません。
bames53 2012年

1

あなたのコード

union {
  struct {
    float x;
    float y;
    float z;
  };
  float v[3];
};

のようなものです

union Foo {
   int;
   float v[3];
};

これは確かに無効です(C99以前)。

その理由はおそらく、(Cで)解析を単純化するためです。その場合、構造体/共用体の本文に「宣言文」だけがあることを確認するだけでよいためです。

Type field;

つまり、gccと「その他のコンパイラ」は名前のないフィールドを拡張としてサポートしています。

編集:匿名構造体がC11で正式にサポートされるようになりました(§6.7.2.1/ 13)。


5
解析の観点からは、union { ... }と何ら変わりはないと思いますstruct { ... }。前者は有効ですが、後者は無効です。
ヨハネスシャウブ-litb 2010

3
C ++の解析が一般的にいかに馬鹿げているかを考えると、解析を単純化するためだけに、許可されていない名前のない構造体や共用体がコミットされているという標準には疑問があります。
エイドリアンマッカーシー、

@エイドリアン:私はC ++ではなくCと言った。C ++はCの構文を採用し、それを拡張します。おそらく、C ++の作成者は、名前のないstruct / unionメンバーを許可して、構文のその部分を混乱させないようにする必要があるとは考えていません。
kennytm

@エイドリアン、グッドポイントエイドリアン、私は常に「実装が難しすぎる」がBjarneとスタッフの懸念になるとは常に思っていませんでした
bobobobo

CとC ++はどちらも名前のない共用体をサポートしているため、union { ... };無効なコメントは正しくありません。
bames53 2012年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.