4

私の「遅延バインディング」を誤解しないでください。実行時の通常の遅延バインディングを意味するのではなく、別のことを意味していて、より適切な言葉を見つけることができません。

これらの値をコンパレーターと比較する必要がContainorある値タイプのコンテナー (または同様の) データ構造に取り組んでいるとします。最初のテンプレートは次のようになります。V

template<typename Val, typename Comp = std::less<Val>>
struct Containor{};

現在、私のContainor構造は別のコンテナを内部的に利用しています。どのコンテナーを使用するかは、テンプレート引数によっても構成可能である必要があります。デフォルトはstd::set. したがって、次のバージョンの は次のContainorようになります。

template<typename Val, typename Comp = std::less<Val>, typename Cont = std::set<Val,Comp>>
struct Containor{};

ここで、コードが私見の匂いを嗅ぎ始めます。ユーザーが内部コンテナーのデフォルトの実装に満足している限り、すべて問題ありません。btree::btree_setしかし、彼が の代わりに新しい google btree セットの実装を使用したいとしますstd::set。次に、彼は次のようにテンプレートをインスタンス化する必要があります。

typedef Containor<int,std::less<int>,btree::btree_set<int,std::less<int>> MyContainor;
                                                     ^^^^^^^^^^^^^^^^^^^

私の問題がある部分に下線を引きました。CLIENT CODE は、適切なパラメーターを使用して btree_set をインスタンス化する必要があります。Containorクラスは常に、最初の 2 つのテンプレート引数とまったく同じ型とコンパレータのセットを必要とするため、これは正直言って最悪です。クライアントは - 偶然にも - ここに他のタイプを挿入することができます! さらに、クライアントには適切なパラメータを選択するという負担があります。この場合、これは簡単かもしれませんが、たとえば内部コンテナーが値型と他の型のペアのセットでなければならない場合は困難です。その場合、クライアントは内部セットの型パラメーターを正しく取得するのにさらに苦労します。

だから私が望むのは、クライアントコードが生のテンプレートのみを渡し、Containor内部で正しい引数でそれをインスタンス化する方法です。つまり、次のようなものです。

template<typename Val, typename Comp = std::less<Val>, typename Cont = std::set >
struct Containor{
    typedef Cont<Val,Comp> innerSet; 
//  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ container instanciates the inner containor
};

typedef Containor<int,std::less<int>,btree::btree_set> MyContainor;
//                                   ^^^^^^^^^^^^^^^^
//                         client only hands in  raw template

もちろん、これは有効な C++ ではありません。

そこで、この問題を解決する方法を考えました。私が考えることができる唯一の解決策は、次のように、使用したいすべてのデータ構造の「バインダー クラス」を記述することでした。

struct btree_set_binder{

    template<typename V, typename C = std::less<V>>
    struct bind{
        typedef btree::btree_set<V,C> type;
    }
};

Containorこれで、セットバインダーで自分を定義できます

template<typename Val, typename Comp = std::less<Val>, typename ContBinder = btree_set_binder >
struct Containor{
    typedef btree_set_binder::bind<Val,Comp>::type innerSet; 
//          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ works like a charm
};

これで、ユーザーは必要なバインダー クラスをContainor指定するだけで、適切な引数でインスタンス化されます。したがって、これらのバインダー クラスは私にとっては問題ありませんが、すべてのコンテナーに対してバインダー クラスを作成するのは非常に面倒です。したがって、C++ 11でテンプレート引数を「遅く」バインドする、つまり生のテンプレートをパラメーターとして取得する別のテンプレート内にバインドするより良い方法または簡単な方法はありますか。

4

3 に答える 3

4

独自のコンパレータ特性を作成することもできます。

// Comparator trait primary template

template <typename T> stuct MyComparator
{
    typedef typename T::key_compare type;
};

// Comparator trait non-standard usage example

template <typename U, typename V, int N>
struct MyComparator<WeirdContainer<U, V, N>>
{
    typedef std::greater<V> type;
};

template <typename T, typename Cont = std::set<T>>
struct MyAdaptor
{
    typedef typename MyComparator<Cont>::type comparator_type;
    typedef T value_type;

    // ...
};

この種の構造は通常「アダプター」クラスと呼ばれるため、「コンテナー」の名前を「MyAdaptor」に変更しました。

使用法:

MyAdaptor<int> a;    // uses std::set<int> and std::less<int>

MyAdaptor<double, WeirdContainer<bool, double, 27>> b;

更新:議論に照らして、外側の型引数を完全に削除することもできます:

template <typename Cont> struct MyBetterAdaptor
{
    typedef MyAdaptorTraits<Cont>::value_type value_type;
    typedef MyAdaptorTraits<Cont>::pred_type pred_type;

    // ...
};

このように使用するには:

MyBetterAdaptor<std::set<int>> c; // value type "int", predicate "std::less<int>"

テンプレートのMyAdaptorTraits記述は演習として残します。

于 2013-02-22T17:17:41.007 に答える
2

だから私が欲しいのは、クライアントコードが生のテンプレートのみを渡し、Containorが内部で正しい引数でそれをインスタンス化する方法です。

したがって、必要なのは明らかにテンプレートテンプレートパラメータです。

// std::set has three template parameters, 
// we only want to expose two of them ...
template <typename V, typename C>
using set_with_defalloc = std::set<V,C>;

template<
    typename Val,
    typename Comp = std::less<Val>, 
    template <typename V, typename C> class Cont = set_with_defalloc>
struct Containor{
    typedef Cont<Val,Comp> innerSet; 
    // ...
};
于 2013-02-22T18:15:03.303 に答える
1

template template次のように、パラメータを使用してそれを実行できるはずです。

template<typename Val, typename Comp = std::less<Val>, template <typename...> class ContBinder = std::set>
    struct Containor {
        typedef ContBinder<Val, Comp> innerSet;
        // ...
    };

注:3つのテンプレートパラメーター(3つ目はアロケーター)を使用しますが、他のコンテナーは使用しない場合があるtypename...ため、可変個引数が必要です。std::set

于 2013-02-22T18:28:03.417 に答える