2016-05-15 10 views
8

C++のJavaコレクション風の環境を実装することに興味があります。 これは良いアイデアではないと思いますが、後でそれを実際に使いたくはありませんが、先進のOOPのやり方を学ぶだけです。テンプレートメンバー関数を使用したインターフェイス

私の問題は純粋に仮想関数を持つ基本クラステンプレートcollection<T>です。これらの関数の1つはmap()で、その値はstd::function<R(T)>です。 map()は仮想でなければならないので、どのリターンタイプを使用するべきかはわかりません。メンバー関数テンプレートを仮想にすることはできないため、collection<R>は使用できません。

私のcollection<T>インターフェイスにそのようなmap()メンバー機能を追加するにはどうすればよいですか?

+0

C++標準コンテナの何が問題ですか? –

+2

@πάνταῥεῖOPは学習目的でこれをやろうとしています。 –

+0

何も私はちょうど教育目的のためのそのようなものを実装する方法を知りたい – Exagon

答えて

7

collection<T>インターフェイスにこのようなmapメンバー機能を追加するにはどうすればよいですか?

短い答えは:あなたはありません。私がcollection<int>をいくつか持っていて、それにmapstd::to_stringを入れたいのであれば、collection<std::string>を作る必要があります。しかし、vector_collection<int>vector_collection<std::string>を生成する必要があり、list_collection<int>list_collection<std::string>を生成する必要があるため、タイプ変換自体はvirtualにする必要があります。しかし、あなたはvirtualメンバ関数テンプレートを持つことができないので、これを表現する方法はありません。

これを実行するには、コンテナに入れているすべてのオブジェクトに共通の基本タイプを設定してから、共通のファサードを作成する必要があります。つまり、あなたは実際にcollection<unique_ptr<Object>>しか持っていません。mapはちょうどあなたに異なるcollection<unique_ptr<Object>>を与え、mapはをcollection_facade<std::string, collection<unique_ptr<Object>>>にします。多くの作業とパフォーマンスと型の安全性について完全な無視をすれば、そこに行くことができます。


これはテンプレートの利点です。

template <class T, class A, class F, class R = std::result_of_t<F(T)>> 
std::vector<R, A> map(std::vector<T, A> const& v, F f) { 
    std::vector<R, A> mapped; 
    mapped.reserve(v.size()); 
    for (T const& elem : v) { 
     mapped.push_back(f(elem)); 
    } 
    return mapped; 
} 

か::私はvectorのようなもののためにmapを書きたい場合は、私はちょうどそれを書くことができます

template <class T, class A, class F, class R = std::result_of_t<F(T)>> 
std::vector<R, A> map(std::vector<T, A> const& v, F f) { 
    return std::vector<R, A>(
     boost::make_transform_iterator(v.begin(), f), 
     boost::make_transform_iterator(v.end(), f) 
     ); 
} 

を私は別に、各コンテナのmap()を実装する必要があります - しかし、私はそれをしなければならないでしょうとにかくそして、今私は何も与えていない。さらに、実行時コンテナに依存しないアルゴリズムをどのくらい頻繁に記述していますか?

+0

また、 'allocator'はリバウンドすることもできます。 – Jarod42

0

外部テンプレート機能としてmapを実装します。 たとえば、mapを内部仮想プロデューサと外部テンプレートコンシューマの2段階で分解できます。

template<typename T> struct Collection { 
    // virtual T next(); // Java way 
    // C++ way 
    // In simplest cases you can rely on iterator pairs. 
    struct const_iterator { 
     T const &operator*() const; 
     const_iterator &operator++(); 
    } 
    virtual const_iterator begin() const; 
    virtual const_iterator end() const; 
}; 
template<typename R, typename T> Collection<R> map(
    Collection<T> const &coll, std::function<R(T)> const &f); 

あなたもbegin()end()を否定し、明示的な(部分)テンプレートの特殊化を書くことができ、本質的に複雑なコンテナとモナド組成物を実装します。

関連する問題