3

次のスニペットはVisualStudio2010でコンパイルできませんが、GCCはそれを気に入っています。

namespace Test { 
    class Baz;
    // Adding class Bar; here and removing the class below makes it work
    // with VC++, but it should work like this, shouldn't it?
    void Foo (Baz& b, class Bar& c);
}

namespace Test { 
    class Bar
    {
        // Making this method non-template works
        template <typename T>
        static void Lalala ()
        {
        }
    };
}

int main ()
{
}

私はここで愚かなことをしていますか、それともこれは有効なコンパイラのバグですか?私が得るエラーは次のとおりです。 error C2888: 'void Bar::Foo(void)' : symbol cannot be defined within namespace 'Test'

GCC 4.5.1でコンパイルされます:http://ideone.com/7sImY

[編集]明確にするために、これが有効なC ++であるかどうか(もしそうなら、なぜそうではないか)を知りたいのですが、コンパイルするための回避策は素晴らしいですが、この質問の一部ではありません。

4

4 に答える 4

2

そうですね、codepad.orgでも試してみましたが、コンパイルできるかどうかはわかりません(C ++コンパイラの機能にそれほど精通していません)。

回避策:前方宣言も行うか、作成する前Barに定義する必要があります。言い換えると、これはMSVCでコンパイルされます。BarFoo

namespace Test 
{ 
    class Baz;
    class Bar;// also forward-declare Bar
    void Foo (Baz& b, class Bar& c);
}

namespace Test 
{ 
    class Bar
    {
        template <typename T>
        static void Foo ()
        {
        }
    };
}

int main(void)
{

    return 0;
}

更新: これはすでにMicrosoftに報告されたバグである可能性があると思います...これはかなり近いように見えます:http://connect.microsoft.com/VisualStudio/feedback/details/99218/invalid-error-c2888-when-a- class-is-defined-after-it-is-declared

Microsoftが引用した回避策:

A stand-alone forward declaration consists of an elaborated type specifier followed by a semicolon.

insert the declaration

class C2888;

before the declaration of foo(C2888o, C2888). 
于 2011-11-09T19:18:28.353 に答える
1

おそらくそれはコンパイラのバグです。

パラメータの順序を変更すると、コンパイル結果が変更されます。

namespace Test { 
void Foo (class Bar& b, class Baz& c) - will compile.
}
于 2011-11-09T19:34:34.547 に答える
1

コードは整形式だと思います。しかし、それを確実に証明するには、標準に使用法と矛盾するものがないことを確認する必要があります。

C ++ 11標準からのいくつかの関連する引用:

3.3.2 p6:

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

  • クラスキー識別子の形式の精巧なタイプ指定子の場合
    • 名前空間スコープで定義された関数のdecl-specifier-seqまたはparameter-declaration-clauseでelaborated-type-specifierが使用されている場合、識別子は宣言を含む名前空間でクラス名として宣言されます。それ以外の場合、フレンド宣言を除いて、識別子は、宣言を含む最小の非クラス、非関数プロトタイプスコープで宣言されます。

3.4.4 p2:

elaborated-type-specifierにnested-name- specifierがなく、elaborated-type-specifierが次の形式の宣言に含まれていない場合: class-key attribute-specifier-seqoptidentifier 識別子; は3.4に従って検索されます。 .1ただし、宣言されている非型名は無視します。... elaborated-type-specifierがclass-keyによって導入され、このルックアップで以前に宣言されたtype-nameが見つからない場合、またはelaborated-type-specifier が次の形式の宣言に表示される場合: class-key属性 -specifier -seqopt識別子 ;elaborated-type-specifierは、3.3.2で説明されているクラス名を導入する宣言です。

7.1.6には、elaborated-type-specifierが構文的にtype -specifierになることができることを確立するいくつかの構文定義があります。7.1は、型指定子が構文的にdecl-specifierになることができることを確立します。これは、関数パラメーター宣言(8.3.5)で型として使用される構文単位です。

于 2011-11-09T19:55:57.490 に答える
-2

class Bar構成に誤りがあります。たまたま、使っていないCプログラマーtypedef struct { /* members */ } Fooですか?

とにかく、テスト内でBarとBazの両方を定義する必要があります。

namespace Test {
    class Bar;
    class Baz;
};

また、関数パラメーターを宣言するときは、、、、およびキーワードを削除classしてください。structunionenum

この変更により、g++4.6でクリーンにコンパイルされます。

于 2011-11-09T19:16:01.583 に答える