43

これはフォローアップの質問です。

前の質問で、@JohannesSchaub-litb は、次のコードは完全に標準に準拠していないと述べました。

class { int i; };  //unnamed-class definition. § 9/1 allows this!

そして彼はこう付け加えた。

文法的には有効ですが、そのようなクラスは少なくとも 1 つの名前をそれを囲むスコープで宣言する必要があるという規則に違反しています。

私はこれを本当に理解できませんでした。彼は何の名前について話しているのですか?

誰かがこれについてさらに詳しく説明できますか(できれば標準を引用してください)?

4

5 に答える 5

51

標準の第 9 節ではclass {public: int i;}(最後のセミコロンがないことに注意してください) 許可されています。これは、名前のないクラスのこのdecl-specifier-seqが、typedef や変数宣言などの他の構成要素で使用される可能性があるためです。class {public: int i;};(最後のセミコロンが存在することに注意してください)の問題は、このクラスの指定が宣言になることです。これは、標準の第 7 項、第 3 項による違法な宣言です。

そのような場合、名前のないビットフィールド (9.6) の宣言を除いて、decl-specifier-seqは 1 つまたは複数の名前をプログラムに導入するか、以前の宣言によって導入された名前を再宣言します。

于 2012-10-30T12:50:49.347 に答える
26

重要なのは、一連のシンボル(この場合は)をclass{ int i; };組み立てていることを宣言することにより、どのコードでも他の場所では使用できなくなるということです。int i

このコードを理解するには、少なくとも次のいずれかを実行する必要があります。

class Myclass { int i; }; //I can furthermore instantiate variables of Myclass
class { int i; } myvar; //This in fact creates a myvar object
typedef class { int i; } MyType; //I can funthermore instantiate variables of MyType

class{ int i; };あなたがコンパイラに言っているだけだと言うことによって:

  • を保持し、intそれに名前を付けますi
  • class私は決して電話しないでそれを包み、そして...
  • 忘れてください!(};

その宣言をプログラムから削除しても、何も変わりません。

于 2012-10-30T12:22:42.173 に答える
11

class { int i; };は、 init-declarator-list のない単純な宣言ですが、クラス名を導入 (または再宣言) していないため、有効な宣言ではありません。

ISO/IEC 14882:2011 7 [dcl.dcl] / 3:

simple-declarationでは、オプションのinit-declarator-listを省略できるのは、クラス (9 節) または列挙型 (7.2) を宣言するとき、つまり、decl-specifier-seqにclass-specifierexlatedtypeのいずれかが含まれているときだけです。 -specifierclass-key (9.1)、またはenum-specifier。これらの場合、およびclass-specifierまたはenum-specifierdecl-specifier-seqに存在する場合は常に、これらの指定子の識別子は、宣言によって宣言されている名前の中にあります ( class-namesenum-names、またはenumeratorとして)、構文に応じて)。そのような場合、名前のないビットフィールド (9.6) の宣言を除いて、decl-specifier-seqは 1 つまたは複数の名前をプログラムに導入するか、以前の宣言によって導入された名前を再宣言します。

于 2012-10-30T12:52:28.500 に答える
10

GCC からのエラー メッセージは、それを非常に簡潔に説明しています。

$ cat > a.cc
class { int i; };
$ g++ -Wall -std=c++98 a.cc
a.cc:1: error: abstract declarator ‘<anonymous class>’ used as declaration

class { int i; }抽象宣言子(標準、§8) ですが、有効な宣言ではありません(§7)。これは @JohannesSchaub-litb が参照したルールです。有効な宣言のためには、クラス名や変数名など、何かを宣言する必要があります。

于 2012-10-30T12:28:35.963 に答える
3

あなたは次のように言う the を破って[basic.scope.pdecl]/6います:

精緻型指定子で最初に宣言されたクラスの宣言のポイントは次のとおりです

class-key attribute-specifier-seqopt identifier ;

識別子は、宣言を含むスコープ内のクラス名であると宣言されています

class-key identifier

名前空間スコープで定義された関数の decl-specifier-seq または parameter-declaration-clause で詳しく説明された型指定子が使用されている場合、識別子は、宣言を含む名前空間でクラス名として宣言されます。それ以外の場合、フレンド宣言を除き、識別子は宣言を含む最小の名前空間またはブロック スコープで宣言されます。[ 注: これらのルールはテンプレート内にも適用されます。— 終了注 ] [ 注: 精緻化された型指定子の他の形式は、新しい名前を宣言しないため、既存の型名を参照する必要があります。3.4.4 および 7.1.6.3 を参照してください。— 終了注記]

  1. 匿名型の変数を作成していません
  2. あなたはタイプを作成していません

[basic.def]/2あなたの例が標準に準拠していないことを証明する標準からの別の例( )があります:

struct S { int a; int b; };       // defines S, S::a, and S::b
struct X {                        // defines X
  int x;                          // defines non-static data member x
  static int y;                   // declares static data member y
  X(): x(0) { }                   // defines a constructor of X
};
int X::y = 1;                     // defines X::y
enum { up, down };                // defines up and down
namespace N { int d; }            // defines N and N::d
namespace N1 = N;                 // defines N1
X anX;                            // defines anX

あなたの例は何も定義していません(フィールドにアクセスできない匿名構造体を除く)。

この場合、使用する 2 つの値が導入されるため、列挙に関する例外に注意してください。

于 2012-10-30T12:56:28.627 に答える