我一直在得到一个非常不寻常的错误,声称类型别名是私有的.经过几个小时的减少我的代码,我得到了以下最小的测试用例:
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 bug吗?
执行以下任何操作可以阻止发生错误:
>将测试转换为类,而不是模板类.
>删除任何功能中的任何语句.
>改变TheCatDog :: Dog :: bark(); to CatDog :: Dog :: bark();.
>删除CrazyHouse类并在Test中合并其内容.
>删除CatDog类,将其内容合并到Test中,并将TheCatDog别名更改为指向Test.
解决方法
标识符上的名称查找CatDog查找被声明为私有的Test :: CatDog.访问是从CrazyHouse执行的,CrazyHouse不是Test的朋友.因此,它是对受保护成员的非法访问.
正如@ sj0h所指出的,在C 11中,您的示例变得有效,因为它们决定以与成员函数相同的方式扩展对嵌套类主体的访问.
C 98:
The members of a nested class have no special access to members of an enclosing class,nor to classes or functions that have granted friendship to an enclosing class; the usual access rules (clause 11) shall be obeyed.
C 11:
A nested class is a member and as such has the same access rights as any other member.
(会员有权访问附上课程的私人会员.)
但是,即使在4.9版本的最新版本中,此更改似乎也未在GCC中实现.所以,为了安全起见,添加朋友声明不会有害.这必须在成员的定义之后:
friend struct CrazyHouse;
请注意,这与C 11更改完全不同,因为友谊不是传递的,而嵌套成员资格授予的访问权限是.