4

私のプログラムの目的は、クラス階層で静的ポリモーフィズムを使用しながら、一連の静的ビジターでアクセスできるデータのリストを作成することです。

CRTP を介して静的ポリモーフィズムを利用するクラスの階層を作成しました。

class VirtualBaseData {
public:    
    //someVirtualFunction
}

template<typename Derived>
class BaseData<Derived> {
public:
    template<typename Visitor>
    void accept(Visitor &v){
         static_cast<Derived*>(this)->accept(v);
    }
}

class DerivedBaseData1: BaseData<DerivedBaseData> {
public:
    template<typename Visitor>
    void accept(Visitor &v){
         //Specific implementation
    }    
}
class DerivedBaseData2: BaseData<DerivedBaseData> {
public:
    template<typename Visitor>
    void accept(Visitor &v){
         //Specific implementation
    }    
}

DerivedBaseData を格納して、後で反復してアクセスできるようにしたいと考えています。

int main(){
    std::vector<VirtualBaseData*> dataSet;
    dataSet.push_back(new DerivedBaseData1);
    dataSet.push_back(new DerivedBaseData2);
    for(auto it = fifth.begin(); it != fifth.end(); ++it){
        it->accept(); //Error: VirtualBaseData does not have a member function accept
    }
}

静的ビジターを静的ポリモーフィズム階層と結合する方法を探しています。コンテナーでクラスを使用するために、テンプレート クラスではない静的ポリモーフィズムで VirtualBaseData クラスが必要です。ただし、VirtualBaseData クラスをテンプレート クラスにすることができないため、CRTPattern で行ったように、適切な static_cast を派生クラスに作成することができません。

私の質問は、私の静的ポリモーフィズム設定と静的ビジター パターンを保持する優れた戦略を持っている人はいますか?

参考までに: http://hillside.net/plop/2006/Papers/Library/portableProgrammingPL.pdfの 21 ~ 23 ページで説明されているように、静的ビジターを実装しました。

4

3 に答える 3

1

コンパイル時にオブジェクトがいくつ/どのタイプになるかわからない場合は、動的ポリモーフィズムの使用例です (少なくとも、静的ポリモーフィズムのみを使用してそれを行う方法はわかりません)。

ただし...コンパイル時にオブジェクトの正確な数とタイプがわかっている場合は、次のようになります。最小限のコンパイル例を次に示します ( code on ideone ):

#include <iostream>
#include <tuple>
#include <type_traits>
using namespace std;


template<typename Derived>
class BaseData {
public:
    template<typename Visitor>
    void accept(Visitor &v){
         static_cast<Derived*>(this)->accept(v);
    }
};

class DerivedBaseData1: BaseData<DerivedBaseData1> {
public:
    template<typename Visitor>
    void accept(Visitor &v){
        std::cout << "DerivedBaseData1: accepting visitor " << v << std::endl;
    }    
};
class DerivedBaseData2: BaseData<DerivedBaseData2> {
public:
    template<typename Visitor>
    void accept(Visitor &v){
        std::cout << "DerivedBaseData2: accepting visitor " << v << std::endl;
    }    
};

namespace impl {

    template <size_t N> 
    struct num2type {};

    template <size_t Idx, typename T, typename Visitor>
    void accept_impl(Visitor &v, T &&collection, num2type<Idx>) {
        // run accept on current object
        auto &object = std::get<Idx>(collection);
        object.accept(v);
        // move iteration forward
        accept_impl(v, std::forward<T>(collection), num2type<Idx - 1>{});
    }

    template <typename T, typename Visitor>
    void accept_impl(Visitor &v, T &&collection, num2type<0>) {
        // run accept on current object
        auto &object = std::get<0>(collection);
        object.accept(v);
    }
}

template<typename ...Ts, typename Visitor>
void accept(Visitor &v, std::tuple<Ts...> &&collection) {
    using T = decltype(collection);
    impl::accept_impl(v, std::forward<T>(collection), impl::num2type<std::tuple_size<std::decay_t<T>>::value - 1>{});
}


int main() {
    using visitor_type = int;
    visitor_type visitor = 42;

    DerivedBaseData1 a1, a3;
    DerivedBaseData2 a2;
    accept(visitor, std::tie(a1, a2, a3));

    return 0;
}

静的ポリモーフィズムを使用すると、静的コレクション (ここでは a std::tuple) を反復処理し、それぞれに目的の引数を指定して目的のメソッドを呼び出すことができます。

于 2016-06-05T18:50:35.490 に答える
0

あなたが言ったように、単純な解決策はありませんが、静的ではなくランタイムポリモーフィズムを使用することをお勧めします。ランタイム ポリモーフィズムをアーカイブするには、基本クラスで型消去を実行し、適切な非 templte 関数にディスパッチする必要があります。これは、たとえばboost::anyブースト ライブラリからアーカイブできます。Constrain forboost::anyは、保存されているすべてのオブジェクトboost::anyがコピー可能でなければならないということです。boost::anyが適していない場合は、型の消去について詳しくお読みください。

class VirtualBaseData {
public:    
    template <typename T>
    void accept(T& visitor) {
        acceptImpl(boost::any(visitor));
    }
protected:
    virtual void acceptImpl(boost::any const & value ) = 0;
}
于 2016-06-05T16:26:14.250 に答える
0

VirtualBaseData ポインターのベクトルを作成しているため、エラーは正しいです。クラス VirtualBaseData には accept() 関数が含まれていません。

あなたの答えは次 のとおりです。C++ クラス メンバー関数テンプレートを仮想にすることはできますか?

ポリモーフィズムについてもお読みください: http://www.cplusplus.com/doc/tutorial/polymorphism/

于 2016-06-05T16:09:06.347 に答える