2011-12-07 14 views
1

VS2010は部分的にC++ 11をサポートしています。以下のコードをVS2010 RTMでコンパイルします。私はなぜコードCLS()が異なる意味で分析されるのか混乱している。行「decltype(CLS())obj1;」において、CLS()はクラスオブジェクトエンティティを示す。ただし、CLS obj2(CLS());行では、CLS()は関数ポインタを示し、パラメータなしでCLSオブジェクトを再実行します。その行動は期待されていますか?それは標準で記述されていますか? C++ 11 7.1.6.2/1当たりCLS()がC++で異なる意味を持つ理由11

struct CLS 
{ 
    int mi; 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    decltype(CLS()) obj1; 
    obj1.mi = 10; 

    CLS obj2(CLS()); 
    obj2.mi = 10; // error C2228: left of '.mi' must have class/struct/union 

    return 0; 
} 

UPDATE 2011年12月8日

、括弧内の予想される文字列が式です。コンパイラは、文字列が有効な式として解析できるかどうかを確認するだけです。はいの場合、コードは整形式です。したがって、コード "decltype(CLS())obj1;"の場合、 "CLS()"はオブジェクトの相違を示す有効な表現として扱われます。

decltype-specifier: 
    decltype (expression) 

UPDATE 2012年1月3日

Potatoswatter説明なぜ与え、 "CLSのOBJ2(CLSを());"オブジェクト定義以外の宣言です。

式または宣言のいずれかと解釈される可能性のあるものはすべて宣言ですが、それは珍しいことです。 CLS obj2(CLS());パラメータ型CLS()がCLSを返す引数を持たず、戻り型がCLSの関数である関数を宣言します。

答えて

1

他の人からも言われているように、これはMost Vexing Parseです。式または宣言のいずれかと解釈されるものは宣言ですが、それは珍しいことです。 CLS obj2(CLS());は、パラメータタイプがCLS()のファンクションを宣言します。ファンクションは、CLSを戻す引数がなく、戻り型がCLSです。コード「CLS OBJ3(OBJ1

CLS obj2{ CLS() }; 

又は単に

CLS obj2{}; 
+0

"式または宣言のいずれかと解釈されるものはすべて宣言です"。ヨハネスのコメントでは、彼は間違って言った。もう一度あなたと確認したい、それは正しい?はいの場合、このルールがC++標準で定義されている場所を指摘できますか?同意する。 C++ 11の構文は、このような混乱を避けています。 – Jeffrey

+0

@Jeffrey:いいえ、celtschkの間違ったステートメントは、宣言と*定義*間のあいまいさに関するものでした。定義を式に変更することは、Johannesが探している修正になります。 – Potatoswatter

+0

それは私には明らかです。ありがとう、Potatoswatter。 – Jeffrey

2

は、それが期待されている:

それは、 "most vexing parse" として知られているはい。

CLS obj2(CLS()); // function forward declaration. 

CLS obj2 = CLS(); // Creates object zero initialized. 
CLS obj2;   // Creates object default initialized. 
+0

例えば、

CLS obj2(CLS()); // forward declaration CLS obj2(CLS fun()) { // definition return fun(); // use unusual functional argument } CLS foo() { // define a function to use as unusual argument return CLS(); } int main() { CLS obj2(CLS()); // still a forward declaration, even in this context! CLS x = obj2(foo); } 

溶液はC++ 11の均一な初期化を使用することです); \t obj3.mi = 10;正常にコンパイルできます。なぜ "CLS obj2(CLS());"関数の宣言として扱われますが、 "CLS obj3(obj1);"オブジェクト定義として扱われますか?彼らは似たような形をしています。なぜCLS obj2(CLS());のCLS()一時オブジェクト定義として扱われますか? – Jeffrey

+0

C++構文は複雑なので、ここを参照してください。http://www.nongnu.org/hcb/#block-declaration –

+0

@Jeffrey: 'obj1'は変数で、' CLS'は型です。 – ildjarn

1

引数がdecltypeの場合、式が必要です。 CLS()の式として解釈する唯一の方法は、それをタイプCLSのデフォルト構築オブジェクトとして解析することです。

しかし、CLS obj2(CLS())(BTWはC++ 03と同じ方法で動作します)には、という2つの可能なパーズがあります.1つは関数宣言で、もう1つはオブジェクト定義です。関数の宣言では、外側のカッコがパラメータリストを構成し、型やオプションの名前を指定することで、パラメータ(またはそのリスト)を指定することが期待されます。その解析では、CLS()は関数型として解釈されます。

その他の有効な解析は、オブジェクトの定義と同じです。その解析のために、もちろんかっこの中には、式CLSのデフォルト構築オブジェクトとしてCLS()の解釈を与える式(またはそれらのリスト)がなければなりません。

C++では、宣言と定義の両方として解析できるものがあれば、宣言として解析されるという規則があります。つまり、この場合、最初の解釈が使用されます。

これは当然、なぜの質問を生み出します。なぜなら、ここで2番目の解釈が明確に予想されるときは、最初の解釈が選択されます。その答えは、それ以外の場合はCの互換性が損なわれるということです(場合によっては期待も)。たとえば、次の行を見て:

int f(); 

今、あなたは右、この機能は引数を取らないとintを返すと宣言されていることを同意するだろうか?しかし、それはタイプintのデフォルト初期化変数の定義として解析することもできます。上記のルールのおかげで、実際にはintを返す関数が宣言されています。

最高の場合には常に期待する結果を与える規則は複雑であるが、おそらく不可能である。関数の宣言はautoで始めたことがないので、これは変数としてそれを解釈するコンパイラを余儀なくされています:C++ 03には、自動変数のためにそれを回避するための簡単な方法はautoで定義の前に付けるためにあったであろうことを

注意定義。 autoの古い意味はC++ 11では削除されていたので、これはもはや機能しません。

+2

"C++では、宣言と定義の両方で解析できるものがあれば、宣言として解析されるというルールがあります。この場合、最初の解釈が使用されます。 - >エラー。 "関数の宣言はautoで始まることはないので、コンパイラはこれを変数定義として解釈することになります。" "しかし、int型のデフォルトで初期化された変数の定義として解析することもできます。" - >エラー。正してください。 –