web-dev-qa-db-ja.com

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

一部のC++コンパイラでは、匿名のユニオンと構造体を標準C++の拡張として許可しています。それは時折非常に役立つ構文糖衣のビットです。

これが標準の一部になるのを防ぐ理由は何ですか?技術的な障害はありますか?哲学的なものですか?それとも、それを正当化する必要性だけでは不十分ですか?

ここに私が話していることのサンプルがあります:

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

私のコンパイラはこれを受け入れますが、 "nameless struct/union"はC++の非標準の拡張機能 であると警告します。

85
Adrian McCarthy

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

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

さらに、C++の匿名構造体にはあまり使用されません。 .v[i]、または.x.y、および.zのいずれかで参照できる3つのフロートを含む構造体を使用するために、あなたが示す使用法は、未定義の結果になると信じていますC++での動作。 C++では、.v[1]などのユニオンの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++の将来の改訂で追加される可能性があります。

43
bames53

vector3を使用することによる宣言union

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

確かに、 匿名構造はMSVC拡張機能でした 。しかし、ISO C11は現在それを許可しており、 gccは許可しています であり、Appleのllvmコンパイラも許可しています。

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

20
bobobobo

よく分からない。 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 };
}

必ずしも非常に便利というわけではありません...厄介なマクロ定義では時々便利です。

6
Dan

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

匿名の構造体またはクラスは、どのような目的を果たしていると思いますか?なぜ標準にないのかを推測する前に、なぜそうあるべきなのかを知りたいのですが、匿名の構造体の使い方はわかりません。

0
David Thornley

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

0
JonM

あなたのコード

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

のようなものです

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

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

その理由は、(Cで)解析を単純化するためにおそらくです。その場合、構造体/ユニオン本体に「宣言子ステートメント」のみがあることを確認するだけでよいからです。 」のような

Type field;

つまり、 gccおよび "other compilers" は、名前のないフィールドを拡張機能としてサポートします。

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

0
kennytm