我从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 ++ bug?
执行以下任何操作可以阻止错误发生:
Test
转换为类,而不是模板类。TheCatDog::Dog::bark();
更改为CatDog::Dog::bark();
。CrazyHouse
类并将其内容合并到Test
。CatDog
类,将其内容合并到Test
并将TheCatDog
别名更改为指向Test
。答案 0 :(得分:5)
标识符CatDog
上的名称查找找到Test::CatDog
,其声明为private
。访问权限来自CrazyHouse
,而friend
不是Test
。因此,这是对受保护成员的非法访问。
正如@ sj0h所指出的,在C ++ 11中,您的示例变得有效,因为他们决定以与成员函数相同的方式扩展对嵌套类主体的访问。
C ++ 98:
嵌套类的成员对封闭类的成员没有特殊访问权限,也没有对已经为封闭类授予友谊的类或函数;应遵守通常的准入规则(第11条)。
C ++ 11:
嵌套类是成员,因此具有与任何其他成员相同的访问权限。
(会员有权访问附上课程的private
名成员。)
但是,即使在4.9版本的最新版本中,此更改似乎也未在GCC中实现。因此,为了安全起见,添加friend
声明不会有什么坏处。 在成员的定义之后必须:
friend struct CrazyHouse;
请注意,这与C ++ 11更改完全不同,因为friend
发送不可传递,而嵌套成员资格授予的访问权限是。
答案 1 :(得分:-1)
根据我们所讨论的C ++版本,编译器的行为可能被视为错误或正确。如果我们讨论的是C ++ 11,那么clang的行为似乎是正确的,如果我们谈论的是C ++ 98,那就是错误的。
stackoverflow项C++ nested class access应该澄清这一点。