C++:奇怪的";是私人的";错误

C++: Strange "is private" error

本文关键字:quot 错误 C++      更新时间:2023-10-16

我从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

对标识符CatDog的名称查找会找到声明为privateTest::CatDog。从不是TestfriendCrazyHouse执行访问。因此,这是对受保护成员的非法访问。

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

C++98:

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

C++11:

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

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

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

friend struct CrazyHouse;

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

编译器的行为可以被认为是错误的或正确的,这取决于我们谈论的C++版本。如果我们谈论C++11,clang的行为似乎是正确的,如果我们谈论C++98,clang的行为则是不正确的。

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