我想要做的是在我的库类中将可变大小的POD作为Pimpl:
// 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标准副本并没有给我任何更好的线索。
如果任何人可以指出任何事情(最好是标准中的一部分)证明这种方式或其他方式(合法或不合法),我将永远感激。
答案 0 :(得分: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
的定义。)
答案 1 :(得分:3)
您的实施不合法:foo::impl
的访问权属于私有,即只有foo
或其成员的定义才能引用它。在实现文件中,您可以在命名空间范围内引用该名称。
该标准的相关部分是11 [class.access]第1段和第4段。