2

私のコンテナは、その要素に関する少しの情報を格納する必要があります。通常、これは要素とは別に保存します。ただし、要素構造型のフィールドを外部で使用するために専用にすることで、ユーザーがメモリを節約できるようにしたいと思います。例えば:

struct MyStuff
{
  int           foo;
  char          bar;
  mutable char  dedicated_for_external_use;  // Because of alignment, this field
                                             // won't increase sizeof (MyStuff)
};

ここでの考え方は、要素のコンテナ以外からフィールドにアクセスしてはならないということです。コンテナは(のように)コピーを格納するため、複数のコンテナにstd::vector任意の値を追加しても問題はありません。x

可能であれば、次の要件を満たすインターフェイスをどのように設計しますか?

  • 完全にオプションである必要があります。つまり、指定されたタイプがそのようなフィールドを提供するかどうかを自動的に判断できるはずであり、コンテナは利用可能な場合にのみそれを使用します。
  • 理想的には、コンパイラとの互換性を最大限に高める必要があるため、型の特性などに依存しないでください。
  • 使いやすいはずです。つまり、タイプに対してこの最適化を有効にすることができ、有効にしたい場合はMyStuff、25行ではなく3行のコードで実行できます。一方、内部の複雑さは問題ではありません。
  • 誤検知を完全に除外することが望ましい。つまり、フィールドをチェックfoo_barすると、まったく関係のない理由でそのようなフィールドが存在する可能性がわずかにあります(そして、ダックタイピングは単にC ++用ではないと思います)。タイプが私のライブラリからマーカークラスを継承しているかどうかを確認するのがより良い方法ProvidesExternalUseFieldです。これは偶然ではないからです。

編集

Boost.Intrusiveについては知っていますが、私が欲しいのは何か違うことです。そのようにして、単一のcharフィールドを持つフッククラスを作成すると、多くの場合、メモリを節約するために使用することはできません。継承されたタイプにint最初のフィールドがある場合、charフィールドは4バイトに埋め込まれます。つまり、このような外部使用フィールドを「スクイーズ」できるようにするには、タイプ内部の複雑な知識が必要になることがよくありますが、継承は実際にはそれを提供しません。

struct hooks { mutable char dedicated_for_external_use; };
struct MyStuff : hooks
{
  int           foo;
  char          bar;
};

ここで、のサイズはMyStuff8バイトではなく12バイトになります。

4

1 に答える 1

0

データ構造体がマーカーインターフェイスから派生する場合は、部分的なテンプレートの特殊化を使用できます。

マーカーインターフェイスクラスが次のようになっているとしましょう。

class ProvidesExternalUseField
{
public:
    char GetExtraField () { return 0; }
    void SetExtraField (char newVal) {}
};

目的のために仮想ではありません。これだけのために、データクラスにvtableポインタを追加したくありません。

次に、単純なコンテナクラスを実装しましょう。

template <class T>
class Container
{
public:
    char GetExtraValue ()
    {
        return 0; // here we cannot know if T is derived from the marker
    }
private:
    T m_t;
};

そして、2つのケースを区別するためにそれを変更する方法は次のとおりです。

template <class T, bool DoesTProvideExternalUseField>
class ContainerImpl
{
public:
    char GetExtraValue () { return 0; }

private:
    T m_t;
};

template <class T>
class ContainerImpl<T, true>
{
public:
    char GetExtraValue () { return m_t.GetExtraField(); } 
private:
    T m_t;
};

template <class T>
class Container: public ContainerImpl<T,
                                      boost::is_base_of<ProvidesExternalUseField,T>::value>
{
};

これで、次のように構造体を定義できます。

struct A
{
    int m_intVal;
};

struct B: public ProvidesExternalUseField
{
    char GetExtraField () { return m_extraField; }
    void SetExtraField (char newVal) { m_extraField = newVal; }

    int m_intVal;
    char m_charVal;
    char m_extraField;
};

そして、まったく同じ方法でコンテナクラスを使用します。

Container<A> a;
Container<B> b;

テンプレートパラメーターとしてpoiter-to-memberを使用することにより、マーカーインターフェイスでゲッターとセッターをさらに自動化(テンプレート化)することもできます。

于 2011-01-26T11:00:02.940 に答える