Законно ли в C ++ 11 наследовать от частного вложенного типа?

То, что я пытаюсь сделать, это иметь 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 не дало мне никакой лучшей подсказки.

Если кто-нибудь может указать мне на что-либо (предпочтительно раздел в стандарте), который доказывает это так или иначе (законно или нет), я был бы вечно благодарен.

3

Решение

Реализация у вас не является законной: доступ к foo::impl является частным, то есть только определение foo или его члены могут ссылаться на него. В файле реализации вы ссылаетесь на имя в области имен.

Соответствующей частью стандарта являются 11 [class.access] пункт 1 и пункт 4.

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определение скрыто).

3

По вопросам рекламы [email protected]