34

すべてのアロケーター クラスには、次のようなインターフェイスが必要です。

template<class T>
class allocator
{
    ...
    template<class Other>
    struct rebind { typedef allocator<Other> other; };
};

また、アロケーターを使用するクラスは、次のように冗長なことを行います。

template<class T, class Alloc = std::allocator<T> >
class vector { ... };

しかし、なぜこれが必要なのですか?

言い換えれば、彼らは次のように言うことができませんでした:

template<class T>
class allocator { ... };

template<class T, template<class> class Alloc = std::allocator>
class vector { ... };

どちらがよりエレガントで、冗長性が低く、(いくつかの同様の状況では) 潜在的に安全ですか?
なぜ彼らはそのrebindルートをたどったのTですか?

(同様の質問がchar_traits他にもあります... すべてが を持っているわけではありませんがrebind、テンプレート テンプレート パラメータの恩恵を受けることができます。)


編集:

ただし、複数のテンプレート パラメーターが必要な場合、これは機能しません。

実際、それは非常にうまく機能します!

template<unsigned int PoolSize>
struct pool
{
    template<class T>
    struct allocator
    {
        T pool[PoolSize];

        ...
    };
};

vectorがこのように定義されている場合:

template<class T, template<class> class Alloc>
class vector { ... };

次に、次のように言うことができます。

typedef vector<int, pool<1>::allocator> int_vector;

そして、(冗長に) 2回言う必要がなくても、完全にうまく機能します.int

そして、rebind内部の操作はの代わりにvectorなります。Alloc<Other>Alloc::template rebind<Other>::other

4

4 に答える 4

22

Foundations of Algorithms in C++11 、Volume 1、 chap 4、p. 35:

template <typename T> 
struct allocator 
{  
   template <typename U>  
   using  rebind = allocator<U>; 
}; 

使用例:

allocator<int>::rebind<char> x;

The C++ Programming Language 、第4 版、セクション 34.4.1、p. 998、デフォルト アロケーター クラスの「クラシック」リバインド メンバーにコメント:

template<typename U>
     struct rebind { using other = allocator<U>;};

Bjarne Stroustrup は次のように書いています。

興味深い rebind テンプレートは古風なエイリアスです。次のようになっているはずです。

template<typename U>
using other = allocator<U>;

ただし、アロケータは、そのようなエイリアスが C++ でサポートされる前に定義されていました。

于 2013-09-08T09:12:44.107 に答える
13

しかし、なぜこれが必要なのですか?

アロケータクラスに複数のテンプレート引数がある場合はどうなりますか?

インスタンス化サイトで少し冗長性がある場合でも、通常のテンプレート引数を使用することを優先して、テンプレートテンプレート引数を使用することが一般的に推奨されない理由については、これでほぼ同じです。多くの場合(ただし、アロケータの場合はおそらくそうではありません)、その引数は常にクラステンプレート(たとえば、テンプレートメンバー関数を持つ通常のクラス)であるとは限りません。

内部構文の一部を単純化するという理由だけで、テンプレートテンプレートパラメータを使用すると(コンテナクラスの実装内で)便利な場合があります。ただし、ユーザーが使用したいアロケーターとしてマルチ引数クラステンプレートを持っているが、ユーザーに単一引数クラステンプレートであるアロケーターを提供するように要求する場合、事実上、ユーザーにほぼのラッパーを作成するように強制します。彼がそのアロケータを使用しなければならない新しいコンテキスト。これは拡張性がないだけでなく、非常に不便になる可能性もあります。そして、現時点では、そのソリューションは、当初考えていた「エレガントで冗長性の低い」ソリューションとはほど遠いものです。2つの引数を持つアロケータがあるとしましょう。ユーザーにとって最も簡単なのは、次のうちどれですか。

std::vector<T, my_allocator<T,Arg2> > v1;

std::vector<T, my_allocator_wrapper<Arg2>::template type > v2;

基本的に、実装の要求を満たすためだけに、ユーザーに多くの役に立たないもの(ラッパー、テンプレートエイリアスなど)を作成するように強制します。カスタムアロケータクラスの作成者にネストされた再バインドテンプレート(単なる単純なテンプレートエイリアス)を提供するように要求することは、代替アプローチで必要なすべてのゆがみよりもはるかに簡単です。

于 2012-09-11T04:07:42.177 に答える
5

あなたのアプローチでは、アロケーターを単一のパラメーターを持つテンプレートにすることを強制していますが、これは常にそうであるとは限りません。多くの場合、アロケーターは非テンプレートにすることrebindができ、ネストされたアロケーターは同じ型のアロケーターを返すことができます。それ以外の場合、アロケータは追加のテンプレート引数を持つことができます。この 2 番目のケースは std::allocator<>、実装がデフォルト値を提供する限り、標準ライブラリ内のすべてのテンプレートが追加のテンプレート引数を持つことが許可されているケースです。また、リバウンド タイプを取得するために使用できるの存在はrebind、場合によってはオプションであることに注意してください。allocator_traits

rebind標準では、ネストされたものは実際にはテンプレート化された型定義にすぎないと実際に述べています。

§17.6.3.5/3 注 A: 上記の表のメンバ クラス テンプレート rebind は、実質的に typedef テンプレートです。[注: 一般に、名前 Allocator が にバインドされている場合SomeAllocator<T>Allocator::rebind<U>::otherは と同じ型です。SomeAllocator<U>ここで、 someAllocator<T>::value_typeは T であり、SomeAllocator<U>::value_typeU です。 — 末尾の注記] Allocator がフォームのクラス テンプレートのインスタンス化である場合SomeAllocator<T, Args>、Args は 0 個以上の型です。引数であり、Allocator は rebind メンバー テンプレートを提供しないため、標準の allocator_traits テンプレートがデフォルトSomeAllocator<U, Args>で代わりに使用さAllocator:: rebind<U>::otherれます。上記のフォームのテンプレートのインスタンス化ではないアロケーター型の場合、デフォルトは提供されません。

于 2012-09-11T03:53:27.913 に答える
0

あらゆる種類のベクトルを取る関数を書きたいとします。

それから、書くことができる方がはるかに便利です

template <class T, class A>
void f (std::vector <T, A> vec) {
   // ...
}

書くよりも

template <class T, template <class> class A>
void f (std::vector <T, A> vec) {
   // ...
}

ほとんどの場合、そのような関数はとにかくアロケータを気にしません。

さらに、アロケータはテンプレートである必要はないことに注意してください。割り当てる必要がある特定の型に対して個別のクラスを作成できます。

アロケータを設計するさらに便利な方法は、おそらく

struct MyAllocator { 
   template <class T>
   class Core {
      // allocator code here
   };
};

それなら書くことができたでしょう

std::vector <int, MyAllocator> vec;

やや誤解を招く表現ではなく

std::vector <int, MyAllocator<int> > vec;

MyAllocatorを追加した後に上記をアロケーターとして使用できるrebindかどうか、つまり、以下が有効なアロケーター クラスであるかどうかはわかりません。

struct MyAllocator { 
   template <class T>
   class Core {
      // allocator code here
   };

   template <class T>
   struct rebind { using other=Core<T>; };
};
于 2015-08-02T11:00:55.313 に答える