2012-11-14 62 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