0

シナリオ (参照用に以下のコードを参照):

  1. 元の (ベース) 実装には、リストを返す func1() が必要です。内部的には、マージとスプライスを呼び出します。
  2. 後続の (派生) 実装には、ベクトルを返す func1() が必要です。ランダムアクセスが必要です。
  3. func2() は両方の実装に共通であり、単純に前方反復子が必要です。

    #include <iostream>
    #include <list>
    #include <vector>
    
    
    class Base {
    protected:
        virtual void func1(std::list<int>& l /* out parameter */) {
            // This must use list. Calls merge and splice.
            std::cout << "list version of func1 in base\n";
        }
    
        virtual void func1(std::vector<int>& v) {
            // This should never be called, but code won't compile without it.
            std::cout << "vector version of func1 in base\n";
        }
    
        template <class T> void func2(T container) {
            typename T::const_iterator it = container.cbegin();
            // Iterate and perform work. Common to both Base and Derived.
            std::cout << "func2 in base\n";
        }
    
        template <class T> void processHelper() {
            T container;
            func1(container);
            func2<T>(container);
        }
    
    public:
        virtual void process() {
            processHelper<std::list<int> >();
        }
    
    };
    
    class Derived : public Base {
    protected:
        virtual void func1(std::vector<int>& v /* out parameter */) {
            // This must use a random access container.
            std::cout << "Vector version of func1 in derived\n";
        }
    
    public:
        virtual void process() {
            processHelper<std::vector<int> >();
        }
    };
    
    int main(int argc, const char * argv[])
    {
        std::vector<int> var;
        Derived der;
        der.process();
    
        //std::list<int> var;
        //Base bs;
        //bs.process();
    
        std::cout << "done\n";
    }
    

目標:

  1. コードの複製 (カット アンド ペースト) がない (または最小限)。
  2. Boost でのコンパイルは避けてください。(まだ必要ではありません。これは必要ありません。)これにより、いくつかの any_iterator 実装が除外されます。

質問:

私がやっていることを達成するために C++ でより良い OO 設計はありますか? func1() から戻る前に、リストをベクターに変換したくない、またはその逆をしたくない理由があります。具体的には、この時点ではリストが大きいため、余分なコピーが発生しないようにしたいと考えています。opaque_iterator http://www.mr-edd.co.uk/code/opqitを返すように func1() を設計することもできましたが、不明なヘッダー ファイルを取り込むことをためらっていました。

いずれにせよ、この問題は独自のアカデミック ライフを帯びていました。この問題は、Java ではコレクションが共通のインターフェースを実装しているため非常に簡単ですが、C++ では難しいようです。この関数を呼び出す実行パスがないにもかかわらず、コードをコンパイルするためだけに Base::func1(std::vector& v) を実装しなければならないという醜さに特に悩まされています。もっと簡単な方法があることを願っていますが、もっと簡単な解決策は見当たりません。

4

3 に答える 3

0

一般的な方法はfunc1、出力イテレータを取ることです:

template<class OutputIterator> void func1(OutputIterator &&out) {
    :

back_insert_iterator次に、出力に使用するコンテナーで を使用して呼び出します。

std::list<int> tmp;
obj->func1(std::back_inserter(tmp));
于 2013-11-07T17:15:49.010 に答える
0

C++ の方法では、反復子を使用します。標準アルゴリズムを使用して、ほとんど何でも行うことができます。ライブラリはコンテナ <--> イテレータ <--> アルゴリズムで意図的に分離されています

コンテナーはイテレーター (基本的には美化されたポインター) を定義し、アルゴリズムはイテレーターで動作します。コンテナとアルゴリズムは互いに未知です。

container.begin()通常、いくつかのイテレータ (通常はと)を渡しcontainer.end()、アルゴリズムはそれらに関して実装されます。

標準アルゴリズムを見て、やりたいことの解決策を思いつくことができるかどうかを確認してください。そのためには、コンテナではなくイテレータで関数をテンプレート化する必要があります。

それが役立つことを願っています。

于 2013-11-07T16:25:25.917 に答える
0

私は、スタック オーバーフローに関するいくつかの同じ行に沿って多くの質問を見つけました。したがって、これは重複している可能性があります。もしそうなら、お詫びします。関連するリンクを次に示します。

一般的な方法でイテレータまたはコレクションを取る関数を作成する方法は?

汎用反復子

http://www.artima.com/cppsource/type_erasure.html

この記事をモデルにした単純なタイプの消去アプローチを採用しました: http://www.cplusplus.com/articles/oz18T05o/ここで起こっていることをすべて理解しているとは言えませんが、うまくいきます。唯一の欠点は、基になるイテレータを直接公開するのではなく、コンテナ クラスでイテレータ API をラップし、すべてのプリミティブと既知のクラスを返す必要があったことです。したがって、私のコンテナー ラッパーはあまり再利用できません。

他の誰かに役立つことを期待して、以下に書いたコードを投稿しました。

    #include <iostream>
    #include <list>
    #include <vector>

    // Type erasure for returning different std containers based off of: http://www.cplusplus.com/articles/oz18T05o/
    class Container {
    protected:
        class IContainer {
        public:
            virtual ~IContainer() {}

            virtual void setBegin() = 0;
            virtual bool isEnd() = 0;
            virtual int get() = 0;
            virtual void next() = 0;
        };

        template <typename T> class ContainerModel : public IContainer {
        public:
            ContainerModel(const T& container_) : m_container(container_) {}
            virtual ~ContainerModel() {}

            virtual void setBegin() {
                m_cit = m_container.cbegin();
            }
            virtual bool isEnd() {
                return (m_cit == m_container.cend());
            }
            virtual int get() {
                return *m_cit;
            }
            virtual void next() {
                ++m_cit;
            }

        protected:
            T m_container;
            typename T::const_iterator m_cit;
        };

        std::shared_ptr<IContainer> m_spContainer;

    public:
        template <typename T> Container(const T& t_) : m_spContainer(new ContainerModel<T>(t_)) {}
        virtual ~Container() {}

        virtual void setBegin() {
            m_spContainer->setBegin();
        }
        virtual bool isEnd() {
            return m_spContainer->isEnd();
        }
        virtual int get() {
            return m_spContainer->get();
        }
        virtual void next() {
            m_spContainer->next();
        }
    };

    class Base {
    protected:
        virtual Container func1() {
            std::cout << "list version of func1 in base\n";
            std::list<int> l;
            // Do lots of stuff with lists. merge(), splice(), etc.
            return Container(l);
        }

        virtual void func2(const Container& container) {
            // Iterate using setBegin(), get(), next() and isEnd() functions.
            std::cout << "func2 in base\n";
        }

    public:
        virtual void process() {
            Container container = func1();
            func2(container);
        }

    };

    class Derived : public Base {
    protected:
        virtual Container func1() {
            std::cout << "Vector version of func1 in derived\n";
            std::vector<int> v;
            // Do lots of stuff with vector's random access iterator.
            return Container(v);
        }
    };

    int main(int argc, const char * argv[])
    {
        Derived der;
        der.process();

        //Base bs;
        //bs.process();

        std::cout << "done\n";
    }
于 2013-11-08T14:30:41.957 に答える