2012-11-14 60 views
3

我所試圖做的是有一個可變大小的POD爲平普爾在我的圖書館類:C++ 11從私有嵌套類型繼承是否合法?

// header file 
class foo { 
public: 
    // ctors, copy, move, dtor, etc. 

private: 
    struct impl; // forward-declared 
    impl* pimpl; // pointer to private implementation 
}; 

然後這樣定義幾個固定大小的實現:

// .cpp implementation file 
struct foo::impl { 
    uint32_t refs; 
    uint32_t size; 
    uint32_t len; 
    uint32_t data; 
}; 

static_assert(sizeof(typename foo::impl) == 16, "paranoia"); 

namespace { // anonymous 
    typedef typename foo::impl base; 

    template <size_t S> 
    struct block : base { 
     static_assert(S > 16, "invalid block size"); 
     static_assert(((S - 1) & S) == 0, "block size must be power of 2"); 

     uint8_t pad[S - 16]; 
    }; 

    typedef block<64> block64; 
    typedef block<128> block128; 
    // ... 
} 

// foo implementation using the above PODs 

版本的GCC 4.6和4.7沒有問題用-std=c++0x -Wall -pedantic編譯,但我仍然對使用私有嵌套類型名稱的合法性感到模糊。通過我的[也許過時的草案] C++ 11標準副本涉水沒有給我更好的線索。

如果任何人都可以指出我的任何東西(最好是標準中的一節),證明這種方式或其他(合法與否),我會永遠感激。

+2

這看起來不合法。 「impl」是私人的,爲什麼任何人都可以訪問它? –

回答

3

您擁有的實施不合法:訪問foo::impl是私人的,即只有foo或其成員的定義可以引用它。在實現文件中,您引用名稱空間作用域中的名稱。

標準的相關部分是11 [class.access]第1段和第4段。

+0

謝謝,迪特馬爾。第11段第4段中的第一個註釋是否意味着,如果在類'foo'聲明中包含公共'typedef impl bar;',那麼在foo外使用名稱'foo :: bar'而不是'foo :: impl'是合法的類範圍?這裏有沒有什麼區別,只是提出「impl」公開聲明? –

+0

我認爲提供可訪問的'typedef'提供了所需的可訪問的名稱。它不會比使本地結構可公開訪問任何不同。 –

3

我認爲這是不允許的。儘管標準中有一個註釋

因爲訪問控制適用於名稱,所以如果將訪問控制應用於typedef名稱,則只考慮typedef名稱本身的可訪問性。沒有考慮typedef引用的實體的可訪問性。

所以在

struct block : base 

名稱base訪問。然而,typedef本身使用名稱foo::impl,這是私人的,因此無法訪問。該名稱在static_assert中也是不可訪問的。

我沒有看到任何允許在這些上下文中訪問名稱的異常。

我的編譯器生成這些錯誤此代碼:

main.cpp:16:27: error: 'impl' is a private member of 'foo' 
static_assert(sizeof(foo::impl) == 16, "paranoia"); 
         ^
main.cpp:4:12: note: declared private here 
    struct impl; // forward-declared 
     ^
main.cpp:19:27: error: 'impl' is a private member of 'foo' 
    typedef typename foo::impl base; 
         ^
main.cpp:4:12: note: declared private here 
    struct impl; // forward-declared 
     ^

一種選擇可能是包括foo公共朋友,這將對內部foo訪問私有名字。然後,您可以在CPP文件的朋友類型的定義,以便它暴露的名字只在一個文件中暴露:

// header 
struct foo { 
    struct private_public_access; 
private: 
    struct impl; 
}; 

// cpp 
struct foo::impl {}; 

struct private_public_access { 
    typedef foo::impl foo_impl; 
}; 

typedef private_public_access::foo_impl base; 

任何人都可以使用的名稱private_public_access,但他們不會有定義,所以無法訪問private_public_access::foo_impl(雖然他們可以自己定義它來獲得訪問權限......)。雖然如果這是可以接受的,那麼也許它可以被公認的名稱foo::impl公開,並且其定義已經隱藏起來(並且像private_public_access的定義已隱藏)。

+0

謝謝。你使用什麼編譯器/版本? –

+0

svn行李鐺 – bames53