Probleme mit Templates



  • EDIT2: Sorry hab im falschen Forum verändert.



  • Vielleicht so etwas?

    template < class T, class Op = IConditionOperand<T> > 
    class ICondition   
    {  
    ...  
       Op * left_; 
       Op * right_; 
    ...
    


  • Danke, es funktioniert auch. Aber verstehe ich es richtig, dass da eigentlich eine beliebige Klasse übergeben werden kann? Sie muss nur ähnliche Schnittstellen wie IConditionOperand anbieten. Oder habe ich da etwas falsch verstanden?



  • template <class T> 
    struct IConditionOperand 
    { 
       T value; 
    }; 
    template < template <typename T> class IConditionOperand>
    class ICondition
    


  • Es kommt leider zu Fehlern:

    template < template <typename T> class IConditionOperand>
    class ICondition
    {
    ...
       IConditionOperand<T> * left_; // Undefiniertes Symbol 'T',
                                     // Ungültige Verwendung des Template 'IConditionOperand',
                                     // Template-Spezialisierung kann aus IConditionOperand' nicht generiert werden.
                                     // Und Deklaration nicht ordnungsgemäß abgeschlossen
    ...
    

    Es liegt warscheinlich am Alter des Compilers.



  • Nein, das geht so nicht.

    Du sagst ihm ja: Als template-Parameter kriegtst Du ein template dessen Parameter übrigens T heißt, das ist ein formaler Parameter, kein Typ.

    Was willst Du denn genau?

    template <typename <typename> MyClass>
    Klasse
    {
      // wir haben hier ein template namens MyClass, kann man zum Beispiel so verwenden:
      MyClass<float> hallo;
      MyClass<int> blub;
      // etc.
    };
    

    Oder willst Du eigentlich nur dieses template für den bei Dir angegeben Parameter instanziieren?

    template <typename T>
    Klasse
    {
      // wir instanziieren MyClass für den Typ T
      MyClass<T> hallo;
    }
    

    Oder willst Du beides variabel haben, sodaß man Typ und template angeben kann?

    template<typename T, typename <typename> MyClass>
    Klasse
    {
      // MyClass ist template
      MyClass<float> blub;
      MyClass<int> hallo;
      // aber auch:
      MyClass<T> test;
    };
    

    Oder eben die obengepostete Variante ohne template-template-Parameter.
    Ich hoffe das stimmt so alles halbwegs.

    MfG Jester



  • gelöscht



  • Jester schrieb:

    Oder willst Du beides variabel haben, sodaß man Typ und template angeben kann?

    Ja, wobei es ein Zeiger sein soll, weil man den Template oder eine abgeleitete Klasse von diesem nehmen soll.

    Also in etwa sowas:

    //ungetestet
    
    template<typename T, typename <typename> MyClass>
    class Klasse
    {
       MyClass<T> * test;
    };
    


  • Und Du bist Dir sicher, daß das MyClass auch ein Parameter sein muß?
    Es geht nicht auch einfach

    template <typename T>
    class Klasse
    {
      MyClass<T> * test;
    };
    

    Ich frag nur, weil mir nicht klar ist, was Du denn erreichen willst und ich im Moment das Gefühl habe Du halst Dir da unnötige Komplexität auf.

    MfG Jester



  • Wieso es zwei Parameter sein müssen kannst Du im Kommentar der main()-Funktion nachlesen

    // Klasse um das Verhalten der Vergleichsoperatoren zu steuern.
    template <class T>
    struct IConditionOperand
    {
    private:
       T value_;
    public:
       T value();
       bool operator ==(IConditionOperand<T> * co) { return value_ == co->value_; }
       bool operator !=(IConditionOperand<T> * co) { return value_ != co->value_; }
       bool operator <(IConditionOperand<T> * co) { return value_ < co->value_; }
       bool operator <=(IConditionOperand<T> * co) { return value_ <= co->value_; }
       bool operator >(IConditionOperand<T> * co) { return value_ > co->value_; }
       bool operator >=(IConditionOperand<T> * co) { return value_ >= co->value_; }
       IConditionOperand(T v) : value_(v) {}
    };
    
    // Andere Möglichkeit, über deren Sinn sich streiten lässt. Aber Zweck vor Sinn!
    template <class T>
    struct NegConditionOperand : public IConditionOperand<T>
    // Alle Vergleiche werden umgedreht
    {
       NegConditionOperand(T value) : IConditionOperand<T>(value){}
    
       bool operator ==(NegConditionOperand<T> * co) { return value_ != co->value_; }
       bool operator !=(NegConditionOperand<T> * co) { return value_ == co->value_; }
       bool operator <(NegConditionOperand<T> * co) { return value_ >= co->value_; }
       bool operator <=(NegConditionOperand<T> * co) { return value_ > co->value_; }
       bool operator >(NegConditionOperand<T> * co) { return value_ <= co->value_; }
       bool operator >=(NegConditionOperand<T> * co) { return value_ < co->value_; }
    };
    
    template < class T >
    class ICondition
    {
    public:
       enum Type { equal, notEqual, less, lessOrEqual, greater, greaterOrEqual };
    private:
       IConditionOperand<T> * left_;
       IConditionOperand<T> * right_;
       Type t_;
    public:
       ICondition() : left_(NULL), right_(NULL){};
       void setLeft(IConditionOperand<T> * l){ 
          if(left_) 
             delete left_;  
          left_ = l; 
       }
       void setRight(IConditionOperand<T> * r){ 
          if(left_)
             delete right_; 
          right_ = r;
       }
       void setOperator(Type t) { 
          t_ = t; 
       }
       virtual bool test() {
          switch(t_){
             case equal:          return (* left_) == right_;
             case notEqual:       return (* left_) != right_;
             case less:           return (* left_) < right_;
             case lessOrEqual:    return (* left_) <= right_;
             case greater:        return (* left_) > right_;
             case greaterOrEqual: return (* left_) >= right_;
             default:             return false;
          }
       }
    };
    
    #pragma argsused
    int main(int argc, char* argv[])
    {
    
       // dann irgendo wird alles aufgerufen
       ICondition<int> c;
       c.setLeft(new NegConditionOperand<int>(20));
       c.setRight(new NegConditionOperand<int>(20));
       c.setOperator(ICondition<int>::equal);
       cout << "(20 == 20) ist ";
       if ( c.test() ){   /* Aus irgendeinem Grund wird operator ==() von 
                             IConditionOperand aufgerufen deswegen dachte ich, 
                             dass wenn man den Typ übergibt, dass dann auch die
                             richtige Funktion aufgerufen wird. */
          cout << "wahr";
       } else {
          cout << "falsch";
       }
       getch();
    
       return 0;
    }
    

    Der Sinn des ganzen ist (man könnte schließlich auch if (20 == 20) { cout << "wahr"; } else { cout << "falsch"; }), dass die if-Schleife(n) zur Laufzeit geparst wird. Templates sind dazu da, weil alle Typen schon zur Compilierzeit bekannt sind.


Anmelden zum Antworten