2016-04-24 2 views
1

Ich versuche, die folgende Strömung zu erzeugen:Aufruf abgeleitete Template-Klasse-Methode von der Basis nicht-Template-Klasse

eine ‚Base‘ Klasse, ohne params oder Funktionalität nur so kann ich Basis Zeiger, halte in eine Methode.

Die abgeleitete Klasse ist eine Vorlage, die operator() für einen gegebenen Template-Argument-Objekttyp implementiert.

Ich versuche, indem Sie einen Zeiger auf die Basisklasse verwenden, den abgeleiteten Klassenoperator() in der Laufzeit aufrufen.

Ich habe versucht, es mit der Umsetzung CRTP (https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern) Aber das scheint nicht die-andere-Wege-um zu arbeiten - wenn die abgeleitete Klasse eine Klassenvorlage ist.

Hier ist mein Code:

class Base {}; 

template<typename Ref_Obj, typename Obj_Type> 
class Derived : public Base { 
    private: 
     typedef bool (Ref_Obj::*Func_p)(Obj_Type) const; 
     Func_p m_func; 
     const Ref_Obj& m_db; 

    public: 
     Derived<Ref_Obj, Obj_Type>(const Ref_Obj& db, Func_p func): m_db(base), m_func(filter) {} 

     inline bool operator()(const Obj_Type& obj) const { 
      return (m_db.*m_func)(obj); 
     } 
} 

Nun ist die Nutzung in einem anderen Klassenvorlage, die Vektor der Basisklasse Zeiger enthält, wie folgt, und haben einen eigenen Operator():

template<typename Obj_Type2> /* Upon usage, Obj_Type2 is the same as Obj_Type, this is just to differ the two in the code here */ 
class BlaBla { 
    private: 
     std::vector<const Base *> m_vec; 

    public: 
     /* relevant constructors ... */ 

     inline bool operator()(const Obj_Type2 &obj) const { 
      for(std::vector<const Base *>::const_iterator it = m_vec.begin(); it != m_vec.end(); ++it) { 

       /*** This is the problematic line V ***/ 
       if((*it).operator()(obj)) { /* DO SOMETHING */ }      
     } 
} 

Natürlich beschwert sich der Compiler, dass es in der problematischen Zeile, die in dem Code unten markiert ist, keine übereinstimmende Funktion gibt, aber die Art, den entsprechenden Aufruf auszuführen, kann ich nicht herausfinden.

erste Lösung in den Sinn kam, einen virtuellen Betreiber zu erstellen ist() (...) mit einem bestimmten Objekttyp z.B. virtueller Operator() (const uint32_t & Obj) in der Basisklasse, die funktioniert, aber meine Absicht ist, dass operator() (...) eine Vielzahl von Objekttypen erhalten wird, und eine virtuelle Methode für jede von ihnen nicht angibt elegant und scheint zu brechen alle Template-Konzept, das ich hier implementieren möchte.

zweite Lösung in dem Sinne kam, irgendwie Ref_Obj und obj_type typenames zu Basisklasse ist vorbei, in einer Art Interface-Methode verwendet werden, das static_cast verwendet den entsprechenden Abgeleitet Operator anrufen (wie in CRTP) - Aber das scheint nicht zu funktionieren, da die abgeleitete Klasse eine Klassenvorlage ist und auch die Klasse BlaBla nicht direkt weiß Ref_Obj typename.

Gibt es eine andere Möglichkeit, den entsprechenden Aufruf an Deriver operator()

+0

Was ist das Spektrum von Typen, die Sie zu abgeleitet 'Operator()' übergeben möchten? Wenn sie alle einen gemeinsamen Vorfahren 'TypeBase' teilen, können Sie das geschützte' virtuelle bool Base :: operator() (TypeBase &) 'und das öffentliche' template bool Base :: operator() (T &) 'als virtuell implementiert erklären , in abgeleiteten Klassen überschrieben. – Mikhail

+0

Sie haben keinen gemeinsamen Vorfahren, da sie Klassenzeiger, primitive Typen usw. sein können. – Adiel

Antwort

1

Es gibt keine klare saubere Art und Weise, dies zu tun zu machen. Das grundlegende Problem ist, dass es keine virtuelle Template-Methode gibt.

Die sauberste Art, wie ich denken kann, dies zu tun, die Löschung vollständig Typs implementiert ist mit einem dynamischen gegossen, und eine virtuelle Methode:

class Base { 
public: 

    virtual bool operator()(const Base &) const=0; 
}; 

template<typename Ref_Obj, typename Obj_Type> 
class Derived : public Base { 
    private: 
     typedef bool (Ref_Obj::*Func_p)(Obj_Type) const; 
     Func_p m_func; 
     const Ref_Obj& m_db; 

    public: 
     Derived<Ref_Obj, Obj_Type>(const Ref_Obj& db, Func_p func): m_db(base), m_func(filter) {} 

     inline bool operator()(const Base& obj) const override { 
      const Obj_Type *derived_obj=dynamic_cast<const Obj_Type *>(&obj); 

      if (!derived_obj) 
      { 
        throw; // Or maybe return false, or something... 
      } 
      return (m_db.*m_func)(*derived_obj); 
     } 
}; 

Obj_Type muss auch von Base abgeleitet werden. Dadurch wird die Aufgabe zur Laufzeit ausgeführt, es gibt jedoch keine Überprüfung der Kompilierzeit.

Der andere Ansatz ist es, den sauren Apfel beißen und 100% Typ Löschung verzichten:

template<typename Obj_Type> 
class Base { 
public: 

    virtual bool operator()(const Obj_Type &) const=0; 
}; 

template<typename Ref_Obj, typename Obj_Type> 
class Derived : public Base<Obj_Type> { 
    private: 
     typedef bool (Ref_Obj::*Func_p)(Obj_Type) const; 
     Func_p m_func; 
     const Ref_Obj& m_db; 

    public: 
     Derived<Ref_Obj, Obj_Type>(const Ref_Obj& db, Func_p func): m_db(base), m_func(filter) {} 

     inline bool operator()(const Obj_Type& obj) const override { 
      return (m_db.*m_func)(obj); 
     } 
}; 

So können Sie immer noch abstrahieren operator() auf einem Gegenstand zu seiner reinen Oberfläche und die Details in der Unterklasse definieren .

Oder eine andere Alternative wäre eine Kombination aus beiden:

class SuperBase { 
public: 

    virtual bool operator()(const Base &) const=0; 
}; 

template<typename Obj_Type> 
class Base : public SuperBase { 
public: 

    virtual bool operator()(const Obj_Type &) const=0; 

    bool operator()(const Base &obj) const override 
    { 
      // Do the dynamic cast check, and forward it to the other 
      // operator(). 
    } 
}; 
+0

Hey, die Basisklasse zu einer Klassenvorlage zu machen, wird es nicht unmöglich machen, einen Vektor von _ "Base *" _ in der _ "BlaBla" _ Klasse, wegen ** unvollständiger Typfehler ** ?? – Adiel

+0

Eine weitere Frage - Alle Ihre Lösungen beziehen sich auf Änderungen in Basis und abgeleiteten Klassen. Die Verwendung dieser vorgeschlagenen Änderungen wird mir helfen, ** operator() (const Obj_Type & obj) ** der _Entgeleiteten Klasse_ aus der Klasse ** BlaBla ** mit einer ** Base * **? (die nicht erbt oder mit den Klassen ** Base oder Derived ** befreundet ist, kennt ihre Definition) – Adiel

+0

In Bezug auf die erste vorgeschlagene Lösung kann ich nicht ** Obj_Type ** von ** Basisklasse ** ableiten, als Obj_Type kann praktisch jeder Typ sein - ein anderer Klassenzeiger, irgendein primitiver Typ, usw. – Adiel