4

私がやろうとしているのは、ライブラリクラスのPimplとして可変サイズのPODを使用することです。

// 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標準のコピーをくぐり抜けても、それ以上の手がかりは得られませんでした。

誰かが私にこれを何らかの方法で(合法であるかどうかにかかわらず)証明する何か(できれば標準のセクション)を指摘することができれば、私は永遠に感謝するでしょう。

4

2 に答える 2

4

これは許されないと思います。標準にはそのメモがありますが

アクセス制御は名前に適用されるため、アクセス制御が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
           ^

1つのオプションは、にパブリックフレンドを含めることです。fooこれにより、内のプライベート名にアクセスできますfoo。次に、そのフレンドタイプの定義をcppファイルに配置して、それが公開する名前がその1つのファイルでのみ公開されるようにすることができます。

// 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の定義は非表示になっています)。

于 2012-11-14T17:53:52.443 に答える
4

あなたが持っている実装は合法ではありません:へのアクセスfoo::implはプライベートです。つまり、の定義fooまたはそのメンバーだけがそれを参照できます。実装ファイルでは、名前空間スコープで名前を参照します。

規格の関連部分は、11[class.access]パラグラフ1およびパラグラフ4です。

于 2012-11-14T17:55:53.407 に答える