7

タイプエイリアスがプライベートであると主張するg ++から非常に珍しいエラーが発生しました。コードを何時間も削減した後、次の最小限のテスト ケースにたどり着きました。

template <typename Dummy>
class Test {
    struct CatDog {
        static void meow ()
        {
            CrazyHouse::TheCatDog::meow();
        }

        struct Dog {
            static void bark ();
        };
    };

    struct CrazyHouse {
        using TheCatDog = CatDog;

        static void startMadness ()
        {
            TheCatDog::meow();
            TheCatDog::Dog::bark();
        }
    };

public:
    static void init ()
    {
        CrazyHouse::startMadness();
    }
};

int main ()
{
    Test<void> t;
    t.init();
}

g++ 4.8.2 のエラーは次のとおりです。

test.cpp: In instantiation of 'static void Test<Dummy>::CatDog::meow() [with Dummy = void]':
test.cpp:19:29:   required from 'static void Test<Dummy>::CrazyHouse::startMadness() [with Dummy = void]'
test.cpp:27:34:   required from 'static void Test<Dummy>::init() [with Dummy = void]'
test.cpp:34:12:   required from here
test.cpp:15:33: error: 'using TheCatDog = struct Test<void>::CatDog' is private
         using TheCatDog = CatDog;
                                 ^
test.cpp:6:41: error: within this context
             CrazyHouse::TheCatDog::meow();
                                         ^

Clang 3.4 は同じコードを受け入れます。ここで何が起こっているのですか、これは g++ のバグですか?

次のいずれかを実行すると、エラーが発生しなくなります。

  • テンプレートTestクラスではなく、クラスに変換します。
  • 関数内のステートメントを削除します。
  • に変わりTheCatDog::Dog::bark();ますCatDog::Dog::bark();
  • クラスを削除し、CrazyHouseその内容を にマージしTestます。
  • クラスを削除し、CatDogその内容を にマージして、エイリアスを にTest変更します。TheCatDogTest
4

2 に答える 2

5

識別子の名前検索により、宣言されているものがCatDog見つかります。アクセスは から実行されますが、これは の ではありません。したがって、保護されたメンバーへの不正なアクセスです。Test::CatDogprivateCrazyHousefriendTest

@ sj0hが指摘しているように、C++ 11では、メンバー関数と同じ方法でネストされたクラスの本体へのアクセスを拡張することを決定したため、あなたの例は有効になります。

C++98:

入れ子になったクラスのメンバーは、囲んでいるクラスのメンバーへの特別なアクセス権も、囲んでいるクラスにフレンドシップを付与したクラスまたは関数への特別なアクセス権もありません。通常のアクセス規則 (第 11 条) に従うものとします。

C++11:

ネストされたクラスはメンバーであるため、他のメンバーと同じアクセス権を持ちます。

private(メンバーには、囲んでいるクラスのメンバーにアクセスする権利があります。)

ただし、この変更は、バージョン 4.9 の最近のビルドでも GCC に実装されていないようです。friendしたがって、安全のために、宣言を追加しても害はありません。これは、メンバーの定義の後に続く必要があります。

friend struct CrazyHouse;

これは C++11 の変更とまったく同じことを達成しないことに注意してくださいfriend。ネストされたメンバーシップによって付与されるアクセスは推移的ですが、ship は推移的ではないためです。

于 2014-02-28T04:46:30.933 に答える
-1

コンパイラの動作は、話している C++ のバージョンに応じて、間違っているか正しいと見なすことができます。C++11 について話している場合、clang の動作は正しく、C++98 について話している場合は正しくないようです。

スタック オーバーフロー項目C++ のネストされたクラス アクセスは、それを明確にする必要があります。

于 2014-02-28T00:40:20.377 に答える