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并将TheCatDog别名更改为指向Test.
4

2 回答 2

5

对标识符进行名称查找会CatDog发现Test::CatDog声明的内容private。访问是从 执行的CrazyHouse,它不是friendTest。因此,这是对受保护成员的非法访问。

正如@sj0h 所指出的,在 C++11 中,您的示例变得有效,因为他们决定以与成员函数相同的方式扩展对嵌套类主体的访问。

C++98:

嵌套类的成员对封闭类的成员没有特殊的访问权限,也没有对已授予封闭类友谊的类或函数的特殊访问权限;应遵守通常的访问规则(第 11 条)。

C++11:

嵌套类是成员,因此具有与任何其他成员相同的访问权限。

(成员有权访问private封闭类的成员。)

但是,即使在最近的 4.9 版本中,此更改似乎也没有在 GCC 中实现。friend因此,为了安全起见,添加声明不会有什么坏处。这必须成员定义之后:

friend struct CrazyHouse;

请注意,这与 C++11 的更改并不完全相同,因为friendship 不是传递性的,而嵌套成员授予的访问权限是传递性的。

于 2014-02-28T04:46:30.933 回答
-1

根据我们谈论的 C++ 版本,编译器的行为可以被认为是错误的或正确的。如果我们谈论 C++11,clang 的行为似乎是正确的,而如果我们谈论 C++98,那么它的行为似乎是错误的。

stackoverflow 项目C++ 嵌套类访问应该澄清这一点。

于 2014-02-28T00:40:20.377 回答