2011-02-10 13 views
5

次のコードは、STDに基づいてコンテナを表します::ベクトルテンプレートとSTL

template <typename Item> 
struct TList 
{ 
    typedef std::vector <Item> Type; 
}; 


template <typename Item> 
class List 
{ 
private 
      typename TList <Item>::Type items; 
    .... 
} 

int main() 
{ 
    List <Object> list; 
} 

は、それがのstd ::ベクトルをテンプレート化し、一般的なコンテナ、そのようなものを作成することは可能ですか?

template <typename Item, typename stl_container> 
struct TList 
{ 
    typedef stl_container<Item>; 
}; 

ここで、stl_containerはstd :: vector、std :: list、std :: set ...を表します。私は創造の時にコンテナのタイプを選びたいと思っています。あなたの答えのための

List <Object, std::vector> list; //vector of objects, not a real code 
List <Object, std::vector> list; //list of objects, not a real code 

おかげで...

更新質問:

は、私は、次のコードを試みたが、エラーがある:

#include <vector> 
template <typename Item, typename Container> 
struct TList 
{ 
    typedef typename Container <Item>::type type; //Error C2059: syntax error : '<', Error C2238: unexpected token(s) preceding '; 
}; 


template <typename T> 
struct vector_container 
{ 
    typedef std::vector<T> type; 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
TList <int, vector_container> v; 
TList <int, map_container> m; 
} 
+0

このクラスは誰が使用しますか?なぜ 'List'は' typedef vector/list/set items'を使用しませんか?コンテナ型と値型を指定すると、これらの2つをまとめてクラスの目的は何でしょうか? – UncleBens

+0

Re:編集しても、 'List > list;'などと書くことができません。 – UncleBens

答えて

5

はいといいえ。

あなたが

template <typename Item, template <typename> class Container> 
struct TList { /* ... */ }; 

は、しかし、一般的には、テンプレートテンプレートパラメータがテンプレートパラメータの数と型が一致する必要があるため、特に有用ではない、例えば、テンプレートテンプレートパラメータを使用することができます。したがって、実際には2つのテンプレートパラメータがあります:1つは値型用、もう1つはアロケータ用ですので、上記は std::vectorと一致しません。テンプレートテンプレートパラメータは、デフォルトのテンプレート引数を利用することはできません。このテンプレートを使用して、あなたのように std::mapテンプレートを使用することはできません、

template <typename Item, template <typename, typename> class Container> 
struct TList { /* ... */ }; 

しかし:

引数としてstd::vectorテンプレートを使用できるようにするには、TListはとして宣言しなければならないであろう引数にはの4つのテンプレートパラメータがあります:キーと値の型、アロケータの型、コンパレータの型です。

通常、この柔軟性がないため、テンプレートテンプレートパラメータを避ける方が簡単です。

+0

'template class Container'を' typename Container' 'Container :: value_type'を使用してコンテナに含まれる型にアクセスしますか? –

+0

@Billy:確か。すべてのコンテナは 'value_type'型定義を持っています。しかし、それはあなたがOPを求めているコンテナを作成することを許さないでしょう。 –

+0

@ジェームズ:ああ - 私は参照してください。 OPがいくつかのイテレータを必要とするように見えます:) –

0

std :: vectorをテンプレート化して一般コンテナを作成することはできますか?

いいえあなたはにコンテナを使用して、関数やオブジェクトをテンプレート化しなければならない - あなたは、コンテナ自体をテンプレート化できませんでした。

たとえば、典型的なstd::findを考慮してください。

template<class InputIterator, class T> 
InputIterator find (InputIterator first, InputIterator last, const T& value) 
{ 
    for (;first!=last; first++) if (*first==value) break; 
    return first; 
} 

これは、任意の容器のために動作しますが、すべてのコンテナとtempalteを必要としません。

また、コンテナに依存しないコードを作成しようとしているように見える場合は、Scott Meyers' Effective STLのコピーを購入したり、アイテム2:コンテナに依存しないコードの錯覚に気を付けてください。うまく

+0

コンテナに依存しないコードの不可能性の原因の一部は、コンテナ/範囲ではなく、イテレータを取るアルゴリズムではありませんか?一般的なfind関数を記述することも可能です。この関数は、setとmapに対しても効率的に動作しますが、このシグニチャでは使用できません。 – UncleBens

+0

@UncleBens:Yes - Effective STLの項目は、誰かがSTLコンテナが提供する機能のみを使用しようとすることを阻止しているので、それらをスイッチアウトすることができます。 (Meyersは私よりも説明が優れています)もしあなたがテンプレートを使ってアルゴリズムをテンプレート化することができれば、是非それを行ってください。(しかし、シーケンスと連想型の両方のコンテナにとって最も効率的であるようにするには、いくつかのテンプレート特殊化が必要でしょう)) –

+0

項目2について:コンテナに依存しないコードの錯覚に注意してください。その精神の下にあるSTL? – kirakun

2

、マクロでそれをハックすることができます

template <typename T, typename stl_container = std::vector<T> > 
struct TList 
{ 
    typedef stl_container Type; 
}; 

#define TLIST(T, C) TList<T, C<T> > 

TList<int> foo; 
TList<int, std::list<int> > bar; 
TLIST(int, std::list) baz; 
+0

なぜあなたはたくさんの子犬を殺したいですか? :P –

+0

私は猫の恋人です;-)。しかし、ええ、これはハックです。 – Tim

+1

私はupvoteまたはdownvoteのどちらかを知らない。 +1。 –

11

はい、ではなく、直接:

template <typename Item, template <typename> class Container> 
struct TList 
{ 
    typedef typename Container<Item>::type type; 
}; 

次に、あなたが別のコンテナのポリシーを定義することができます。

template <typename T> 
struct vector_container 
{ 
    typedef std::vector<T> type; 
}; 

template <typename T> 
struct map_container 
{ 
    typedef std::map<T, std::string> type; 
}; 

TList<int, vector_container> v; 
TList<int, map_container> m; 

しかし、少し冗長です。*直接作業を行うには、the route described by Jamesが必要ですが、これは最終的に非常に柔らかい。

しかし、C++ 0xで我々はうまくこれを行うことができます:

#include <map> 
#include <vector> 

template <typename Item, 
      template <typename...> class Container, typename... Args> 
struct TList 
{ 
    // Args lets the user specify additional explicit template arguments 
    Container<Item, Args...> storage; 
}; 

int main() 
{ 
    TList<int, std::vector> v; 
    TList<int, std::map, float> m; 
} 

パーフェクト。残念ながら、C++ 03でこれを再現する方法はありません。


*「少し冗長」とは、「これは正統性がない」ということを強調したいと思います。あなたの問題に対する正しい解決策は、標準ライブラリが行うことです、as Jerry explainsです。

template <typename Item, typename Container = std::vector<Item>> 
struct TList 
{}; 

しかし、これは大きな問題を残して:あなたは自分のコンテナアダプタのユーザが直接全体のコンテナ型を指定することができ、コンテナの値の型がItemしかしsomething_else<Item>であることを私は何をしたくない場合は?つまり、既存のコンテナの値の型を別のものに変更するにはどうすればよいですか。あなたのケースでは、それ以上読むことはありませんが、私たちの場合、rebindコンテナにしたいと思います。アロケータが行うものの

残念ながら私たちのために、コンテナは、この機能を持っていない:これは私たちがallocator<U>allocator<T>を与え得ることを可能にする

template <typename T> 
struct allocator 
{ 
    template <typename U> 
    struct rebind 
    { 
     typedef allocator<U> type; 
    }; 

    // ... 
}; 

。私たちはこの侵入的なユーティリティなしでコンテナに対して同じことをどうやって行うことができますか? C++ 0xのでは、それは簡単です:

template <typename T, typename Container> 
struct rebind; // not defined 

template <typename T, typename Container, typename... Args> 
struct rebind<T, Container<Args...>> 
{ 
    // assumes the rest are filled with defaults** 
    typedef Container<T> type; 
}; 

std::vector<int>を考えると、我々は例えば、rebind<float, std::vector<int>>::typeを行うことができます。以前のC++ 0xのソリューションとは異なり、この1は、C++ 03のマクロと反復とでエミュレートすることができます。..


**このメカニズムが維持するためにどの引数を指定するように、はるかに強力行うことができますこれは反動するもので、引数として使う前に自分自身を再バインドするものですが、それは読者のための練習として残されています。 :)

+1

良いアイデア。インダイレクションの余分なレイヤーでは解決できない問題はありますか? –

+0

@James:Nope。私は鏡を使うと額を見ることさえできます。 – GManNickG

+0

Lol - それはきちんとしています。コメントは面白いです。 +1。 –

6

私は少し賢明な(そして有能な)人々がいいえを言っていない理由に少し困惑します。

質問を誤解していない限り、達成しようとしていることは、標準ライブラリの「コンテナアダプタ」と事実上同じです。それぞれは、基本的なコンテナタイプへのインタフェースを提供し、使用されるコンテナタイプはテンプレートパラメータ(デフォルト値)として提供されます。

たとえば、std::stackは、他のコンテナ(たとえば、、std::dequestd::listまたはstd::vector)を使用してください。std::stackは、単にスタック操作を使用したい場合に、単純化された/制限付きのインターフェイスを提供しています。 std::stackで使用される基底のコンテナがテンプレートパラメータとして提供されます。ここでのコードは標準でどのように見えるかです:もちろん

namespace std { 
    template <class T, class Container = deque<T> > 
    class stack { 
    public: 
     typedef typename Container::value_type value_type; 
     typedef typename Container::size_type size_type; 
     typedef Container      container_type; 
    protected: 
     Container c; 
    public: 
     explicit stack(const Container& = Container()); 
     bool empty() const    { return c.empty(); } 
     size_type size() const   { return c.size(); } 
     value_type& top()    { return c.back(); } 
     const value_type& top() const { return c.back(); } 
     void push(const value_type& x) { c.push_back(x); } 
     void pop()      { c.pop_back(); } 
    }; 
} 

、おそらく私は質問を誤解してきました - もしそうなら、私は(一種の)不一致だ人と人と事前に謝罪します。

+0

Jerry:OPは 'MyClass 'と書かれたコードが 'std :: vector 'を作成したいと思っています。 'std :: stack'の例では、渡されたtypenameは' std :: deque'ではなく、 'std :: deque ' - クラステンプレートではなくテンプレートクラスです。つまり、あなたのコードはOPが 'MyClass >'をしなければならなくなるでしょう。 –

+0

@Billy O'Neal:私は質問を読み返したが、依然として彼が望んでいるところを見つけることはできない。たぶん私はちょうど十分な睡眠を昨晩か何か得なかった.... –

+0

私は質問のポイントは、テンプレートのパラメータに全体の型を渡すことなくコンテナを取得することだと思う。 (例えば、私は値の型を 'secret_type 'にすることができます)しかし、私はあなたの答えが重要であると私たちは問題を解決すべきであり、質問に答えるだけでなく、これが私たちの大部分の問題です。 – GManNickG

-1

テンプレートテンプレートパラメータは、ここで説明したように使用できます。これに伴う主な難点は、異種のコンテナタイプに異なるテンプレートパラメータがあるわけではなく、標準のコンテナでは、ベクタなどの標準コンテナに、文書化された必要なものだけでなくテンプレートパラメータがあることです。

あなたは適切なテンプレートパラメータを受け入れる独自のサブクラスの種類を提供することにより、この問題を回避して(デフォルト値を持っている必要があります)すべてのエキストラが私の実装に充填させることができます:

template < typename T > struct simple_vector : std::vector<T> {}; 

またはあなたが使用することができますテンプレート付きtypedefイディオム:

template < typename T > struct retrieve_vector { typedef std::vector<T> type; }; 
+3

[C++標準では、実装で追加のオプションのテンプレートパラメータを使用することはできません。](http://stackoverflow.com/questions/1469743/standard-library-containers-with-additional-optional-template-parameters) –

+0

Iあなたが標準的なコンテナから継承するので、下向きです。彼らは仮想デストラクタを持っていないので 'simple_vector 'クラスを 'ベクトル'と期待される場所で使うのは危険です。クラスのユーザはそれを間違える可能性があり、 'simple_vector ::〜simple_vector'の代わりに'ベクトル ::〜vector'を呼び出すことができます。 –

+0

この場合はアレクサンドルではありません。考えてみるのに一瞬でも二度もしてください。それ以上... –

関連する問題