2

仮想テンプレート関数が c++ で許可されていないことを認識しています。私の特定のアプリケーション ドメインのため、アルゴリズムのセットを扱い (ポリモーフィズムと継承による実装は当然)、共通のインターフェイスを適用する必要があります。特定のアルゴリズム クラスはイテレータ上で動作しますが (驚くことではありません)、これらのテンプレート化された関数を介して仮想化を偽造したいと考えています。これは、boost::mpl を使用して思いついたソリューションの例です。これが長いことは承知していますが、これは私が目指しているものをシミュレートするために作成できる最小限のコード例です。私の特定の質問は、コードの後に​​続きます。

#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());
}

では、この「偽の仮想」テンプレート関数の落とし穴は何でしょうか? これを行うためのより簡潔な方法はありますか?

コード標準についても失礼します。それらは私の職場で使用しているものです。

4

1 に答える 1

0

古典的な二重発送パターンに置き換えてみませんか。基本レベルでのクラス階層を知っているようです。そのため、以下を使用します。よく知られている、Visitor または DoubleDispatch パターンで、効率の悪い dynamic_cast を排除します。率直に言って、dynamic_cast<> が表示された場合、私は常にダブル ディスパッチについて考えます。

既知のクラス:

class A;
class B;
class C;

仮想主義の出発点:

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

テンプレート引数の実装:

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;   
};

実際の実装の抽象基本クラス:

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)):

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);
}

二重ディスパッチによる 2 番目の実際の実装 ( VirtualFunc<Iterator>::callFor(C& c)):

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());
}

出力:

Begin::0
Iterator::0
Iterator::1
Iterator::2
Iterator::3
Iterator::4
于 2012-06-24T07:09:33.830 に答える