virtuelle Methodentemplates?



  • Ich weiss, template-methoden koennen nicht virtuell sein, ich habe aber folgendes Problem: Ich habe eine Klasse A, die Objekte beliebigen Typs aufnehmen und abgeben soll, und sie beim Abgeben auch noch in einen evtl. anderen Typ konvertieren soll, bsp:

    class A {
    public:
      template <typename T>
      void take(T const& t);
    
      template <typename U>
      U give();
    };
    
    int main() {
      A a;
      int i = 15;
      a.take(i);
      double d = a.give<double>();
    }
    

    auf dem Weg wuerde ja saemtliche Typinformation verlorengehen, daher weiss ich nicht, ob sowas ueberhaupt moeglich ist. Gibts irgendwelche Ansaetze, das zu erreichen, ohne A selbst zum template zu machen? (in dem Falle waere es ja leicht)

    Den Threadtitel habe ich deshalb gewaehlt, weil ich ueberlegt hatte, eien Typ Holder<T> zu schrieben, der das uebergebene Objekt haelt und A einen Pointer auf eine Basisklasse aller Holder zu geben:

    struct basic_holder {
      template<typename U>
      virtual U give() = 0;  // geht nicht in C++ !
    };
    
    template <typename T>
    struct Holder : public basic_holder {
      T mem;  
    
      Holder(const T& t) : mem(t) {}
    
      template<typename U>
      virtual U give() {return mem}
    };
    


  • Hm, keiner einen Ansatz? Dann wirds wohl darauf hinauslaufen, dass A ein Klassentemplate wird.





  • Soweit ich das überblicken kann nicht, leider. Ich habe folgendes:

    - eine Klassenhierarchie für arithmetische und logische Ausdrücke

    class primal_expression {
    };
    
    template <typename Rtype>
    struct basic_expression : public primal_expression {
      typedef Rtype result_type;
    };
    
    template <typename Rtype, typename LArgtype, typename RArgtype>
    struct binary_expression : public basic_expression<Rtype> {
      typedef LArgtype left_argument_type;
      typedef RArgtype right_argument_type;
    };
    
    //abgeleitet davon korrespondierende Ausdrücke zu allen möglichen operatoren
    

    Da ich für komplizierte geschachtelte Ausdrücke ebenso komplizierte template-typen erhalte, wollte ich eine Klasse Expression haben, die einen Zeiger auf primal_expression enthält und per Methodentemplate das Ergebnis des Ausdrucks im gewünschten Typ zurückgibt (wenn die Konvertierung möglich ist)

    Class Expression {
    primal_expression* exp;
    public:
      template<class T>
      T evaluate();
    };
    

    Da es aber wohl schwer wird zur Laufzeit zu prüfen, ob eine gewünschte Typkonvertierung möglich ist, muss ich mir wohl was anderes überlegen.



  • wieso fängst du deine klassen-hierarchie nicht mit

    template <class T> class expression
    {
    public:
        typedef T result_type;
        virtual T get_result() const = 0;
    };
    

    oder etwas ähnlichem an?



  • das wäre dann bei mir die basic_expresion. Ds bringt mich aber auch nicht weiter, wenn ich eine (templatelose) Klasse als Behälter für alle möglichen Ausdrücke (mit verschiedenen Rückgabetypen) haben möchte. In so einer klasse müsste ich einen Pointer auf primal_expression haben, wo dann nurnoch im dynamischen Typ die Information über den Rückgabetyp steckt.



  • Weiss nicht, so vielleicht:

    class any_result_wrapper
    {
    public:
        virtual ~any_result_wrapper() {}
        virtual type_info const& get_result_type_info() const = 0;
        // + was du halt sonst noch brauchst
    };
    
    template <class T> class basic_result_wrapper : public any_result_wrapper
    {
    public:
        typedef T result_type;
    
        basic_result_wrapper(T const& t) :
            m_result(t)
        {
        }
    
        virtual T get_result() const
        {
            return m_result;
        }
    
        virtual type_info const& get_result_type_info() const
        {
            return typeid(T);
        }
    
    private:
        T m_result;
    };
    
    class any_expression
    {
    public:
        virtual type_info const& get_result_type_info() const = 0;
        virtual boost::shared_ptr<any_result_wrapper> get_any_result() const = 0;
    }; 
    
    template <class T> class basic_expression : public any_expression
    {
    public:
        typedef T result_type;
        virtual T get_result() const = 0;
    
        virtual type_info const& get_result_type_info() const
        {
            return typeid(T);
        }
    
        virtual boost::shared_ptr<any_result_wrapper> get_any_result() const
        {
            boost::shared_ptr<basic_result_wrapper<T> > w(new basic_result_wrapper(get_result()));
            return w;
        }
    };
    

    Allerdings ... rein intuitiv ... ich hab so das Gefühl als ob du das alles garnicht brauchst.
    Vielleicht könntest du mit einer Variant-Klasse arbeiten?
    boost::any wäre eine Möglichkeit, oder auch gern was eigenes wenn weder boost::any noch boost::variant noch sonstige fertige Lösungen passen.



  • Ist alles nicht so ganz das was ich mir vorstelle, aber trotzdem danke fuer die Muehe - boost::variant werd ich mir mal anschauen. Wenn ich das Problem behoben hab (oder eben doch ein Template nutze), werd ich mal berichten. (Oder ich warte auf C++0x mit auto 😛 )



  • Was soll dir auto bringen?
    Ich vermute du erhoffst dir von auto was was es nicht ist, auto ist nämlich genauso statisch, und hilft dir hier nicht.



  • jein. Ein kleines Beispiel sollte es deutlich machen:

    int a, b;
    double d, e;
    
    ???? e = (expr(a) + b) < (expr(d) * e);
    

    Das Ergebnis des Ausdrucks rechts vom = ist vom Typ
    less_expr<add_expr<int,int>, mult_expr<double,double> > und hat den typdef result_type bool und eine Methode bool evaluate(); Es wäre jetzt Schwachsinn zu erwarten, dass ein Klient an stelle der ???? einen beliebig komplizierten Typ hinschreibt, deshalb wollte ich eine Klasse schrieben, deren Ctor alle möglichen expressions akzeptieren soll und das Monstrum in einer Holder-Klasse schachtelt. Mit auto wäre das nichtmehr möglich, wenn ich den Artikel im magazin richtig verstanden hab, da schrieb ich keine holderklasse sondern einfach auto e = .....



  • Ok.
    Wenns dir nur darum geht, das kannst du auch ohne auto zumindest soweit vereinfachen dass der client nurmehr schreiben muss:

    int a, b;
    double d, e;
    
    expression_holder<bool> e = (expr(a) + b) < (expr(d) * e);
    

    Was in den meisten Fällen schon ausreichend sein sollte.
    Und zu implementieren ist das auch trivialst.



  • ajo klar, wollte halt nur gucken obs da ne Möglichkeit ganz ohne tmpl gibt...


Anmelden zum Antworten