2012-05-13 11 views
2

私は、仮想テンプレート関数はC++では使用できないことを認識しています。私の特定のアプリケーションドメインのために、私たちはアルゴリズムのセット(多相性と継承を通して実装するために自然)を扱い、共通のインターフェースを強制する必要があります。特定のアルゴリズムクラスはイテレータで動作します(驚くべきことではありません)。しかし、これらのテンプレート関数を通して仮想化を偽装したいと考えています。 boost :: mplを使って思いついた解決策の例を次に示します。これは時間がかかることに気づいていますが、これは私が目指しているものをシミュレートするために作成できる最小限のコード例です。私の具体的な質問はコードの後に​​続きます。仮想テンプレート関数の偽装C++

#include <iostream> 
#include <vector> 
#include <boost/mpl/list.hpp> 
#include <boost/mpl/for_each.hpp> 

using namespace std; 

class A; 
class B; 
class C; 

typedef boost::mpl::list<B, C> DerivedClassList; 

template<typename Base, typename Iterator> 
struct VirtualFunc{ 
    public: 
    VirtualFunc(Base* _memory, Iterator _begin, Iterator _end) : 
     m_memory(_memory), m_begin(_begin), m_end(_end){} 

    template<typename T> 
     void operator()(T& _t) { 
     T* tptr = dynamic_cast<T*>(m_memory); 
     if(tptr != NULL){ 
      tptr->Print(m_begin, m_end); 
     } 
     } 

    private: 
    Base* m_memory; 
    Iterator m_begin, m_end; 
}; 

class A{ 
    public: 
    A(){} 
    virtual ~A(){} 

    template<typename Iterator> 
     void Print(Iterator _begin, Iterator _end){ 
     boost::mpl::for_each<DerivedClassList>(VirtualFunc<A, Iterator>(this, _begin, _end)); 
     } 
}; 

class B : public A { 
    public: 
    B(){} 
    virtual ~B(){} 

    template<typename Iterator> 
     void Print(Iterator _begin, Iterator _end){ 
     cout << "Begin::" << *_begin << endl; 
     } 
}; 

class C : public A { 
    public: 
    C(){} 
    virtual ~C(){} 

    template<typename Iterator> 
     void Print(Iterator _begin, Iterator _end){ 
     for(Iterator it = _begin; it!=_end; it++) 
      cout << "Iterator::" << *it << endl; 
     } 
}; 

int main(){ 
    vector<size_t> numbers; 
    for(size_t i = 0; i<5; i++) 
    numbers.push_back(i); 

    A* printBegin = new B(); 
    A* printAll = new C(); 
    //faking virtualism will print just begin 
    printBegin->Print(numbers.begin(), numbers.end()); 
    //faking virtualism will print all 
    printAll->Print(numbers.begin(), numbers.end()); 
} 

だから、この「偽の仮想」テンプレート機能の落とし穴は何ですか?これを行うより簡潔な方法がありますか?

また、コードの基準を言い訳すると、私たちは職場で使用しています。

+0

これは、[コードレビュー](http://codereview.stackexchange.com/)のためのより良い適しているかもしれません。 –

+0

ありがとう、私は今そこにこれを投稿します。 – pippin1289

答えて

0

古典的なダブルディスパッチパターンで置き換えてみませんか?基本レベルでクラス階層を知っているようです - 次のように使用します。それはよく知られているVisitorまたはDoubleDispatchパターンであり、非効率的なdynamic_castを排除します。

class A; 
class B; 
class C; 

仮想イズムのスタート地点:テンプレート引数の

class IVirtualFunc { 
    public: 
    virtual void callFor(B& memory) = 0; 
    virtual void callFor(C& memory) = 0; 
}; 

実装: - 率直に言って私は<のdynamic_castを見れば>私はいつもダブルディスパッチ、

既知claseesについて考えます

template<typename Iterator> 
class VirtualFunc : public IVirtualFunc { 
    public: 
    VirtualFunc (Iterator _begin, Iterator _end) : begin(_begin), end(_end) {} 
    virtual void callFor(B& memory); 
    virtual void callFor(C& memory); 
    private: 
    Iterator begin; 
    Iterator end; 
}; 

実際の私の抽象基本クラスmplementations:それのための二重の発送と

class A{ 
    public: 
    template<typename Iterator> 
    void Print(Iterator _begin, Iterator _end) { 
     VirtualFunc<Iterator> vFunc(_begin, _end); 
     dispatch(vFunc); 
    } 
    virtual void dispatch(IVirtualFunc&) = 0; 
}; 

まず実際の実装(VirtualFunc<Iterator>::callFor(B& b)):それのための二重派遣(VirtualFunc<Iterator>::callFor(C& c))と

class B : public A { 
    public: 
    B(){} 
    virtual ~B(){} 

    template<typename Iterator> 
     void Print(Iterator _begin, Iterator _end){ 
     cout << "Begin::" << *_begin << endl; 
     } 
    virtual void dispatch(IVirtualFunc& vf) { vf.callFor(*this); } 
}; 

template<typename Iterator> 
void VirtualFunc<Iterator>::callFor(B& b) 
{ 
    b.Print(begin, end); 
} 

第二に、実際の実装:

class C : public A { 
    public: 
    C(){} 
    virtual ~C(){} 

    template<typename Iterator> 
     void Print(Iterator _begin, Iterator _end){ 
     for(Iterator it = _begin; it!=_end; it++) 
      cout << "Iterator::" << *it << endl; 
     } 
    virtual void dispatch(IVirtualFunc& vf) { vf.callFor(*this); } 
}; 
template<typename Iterator> 
void VirtualFunc<Iterator>::callFor(C& c) 
{ 
    c.Print(begin, end); 
} 

プルーフそれは動作します:

int main(){ 
    vector<size_t> numbers; 
    for(size_t i = 0; i<5; i++) 
    numbers.push_back(i); 

    A* printBegin = new B(); 
    A* printAll = new C(); 
    //faking virtualism will print just begin 
    printBegin->Print(numbers.begin(), numbers.end()); 
    //faking virtualism will print all 
    printAll->Print(numbers.begin(), numbers.end()); 
} 

OUTPUT:

Begin::0 
Iterator::0 
Iterator::1 
Iterator::2 
Iterator::3 
Iterator::4