2014-02-28 91 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船是不可傳遞的,而通過嵌套成員授予訪問權限是。