2014-02-28 70 views
7

我一直在从g ++声称一个类型别名是私人的非常不寻常的错误。之后减少我的代码的时间,我已经得出了以下的最小测试案例:C++:奇怪的是“私人”的错误

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(); 
             ^

锵3.4接受相同的代码。这里发生了什么,这是一个g ++的bug?

进行下列任何操作,从发生的历史停止错误:

  • 谈到Test成一类,而不是一个模板类。
  • 删除任何函数中的任何语句。
  • TheCatDog::Dog::bark();更改为CatDog::Dog::bark();
  • 删除CrazyHouse类并合并它的内容Test
  • 删除CatDog类,将其内容合并到Test中并将TheCatDog别名更改为指向Test
+2

最有可能的是。 – Shoe

回答

-1

根据我们正在讨论的C++版本,编译器的行为可能被认为是错误或正确的。看起来,如果我们在谈论C++ 11时,clang的行为是正确的,如果我们正在谈论C++ 98,那么它是不正确的。

该计算器项目C++ nested class access应该澄清。

+0

我相信你在这里是错误的,嵌套类应该有权访问它所嵌套类的私有成员。示例:http://ideone.com/wFeE37 –

+3

这种可访问性似乎在C++ 03和C之间发生了变化++ 11。 http://stackoverflow.com/questions/6998369/c-nested-classes-accessibility – sj0h

+0

@ sj0h感谢您的链接。这解释了行为的差异。 –

5

在标识符CatDog上的名称查找发现Test::CatDog,其被声明为private。访问从CrazyHouse执行,其不是的Test。因此,这是对受保护成员的非法访问。

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

C++ 98:

嵌套类的成员具有一种封闭类的成员没有特殊的访问,也不限于已授予的友谊的封闭类的类或功能;应遵守通常的访问规则(第11条)。

C++ 11:

嵌套类是一个部件,因此具有相同的访问权限的任何其它构件。

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

但是,这种变化不会出现在GCC甚至在最近构建的4.9版本中实现。所以,为了安全起见,添加friend声明无妨。这必须成员的定义后去

friend struct CrazyHouse; 

请注意,这不完成完全一样的C++ 11的变化,因为friend船是不可传递的,而通过嵌套成员授予访问权限是。