Design Problem



  • mit einer partiellen template-spezialiserung?



  • #include <iostream>
    
    class AlgoBase
    {
        public:
            template <typename T>
            void calc()
            {
                Step1();
                Step2_TemplateMethod(T);
                Step3();
            }
    
        protected:
            virtual void Step2_TemplateMethod()=0;
    
            virtual ~AlgoBase() {}
    
        private:
            void Step1() {std::cout << "Step1" << std::endl;}
            void Step3() {std::cout << "Step3" << std::endl;}
    };
    
    class Algo1 : public AlgoBase
    {
        void Step2_TemplateMethod( "Äpfel") { //do something }
    };
    
    class Algo2 : public AlgoBase
    {
        void Step2_TemplateMethod( "Häuser") { //do something }
    };
    

    also ich möchte Step2_TemplateMethod in zwei Unterklassen jeweils für einen best Typ implmentieren und der AlgoBase soll dann mit eben abhg vom Typ die richtige Implmentierung wählen.

    Klar was ich meine?



  • #include <iostream>
    
    class AlgoBase
    {
        public:
            template <typename T>
            void calc( T mytype)
            {
                Step1();
                Step2_TemplateMethod(mytype);
                Step3();
            }
    
        protected:
            virtual void Step2_TemplateMethod()=0;
    
            virtual ~AlgoBase() {}
    
        private:
            void Step1() {std::cout << "Step1" << std::endl;}
            void Step3() {std::cout << "Step3" << std::endl;}
    };
    
    class Algo1 : public AlgoBase
    {
        void Step2_TemplateMethod( othertype1 ) { //do something }
    };
    
    class Algo2 : public AlgoBase
    {
        void Step2_TemplateMethod( othertype2 ) { //do something }
    };
    


  • Willst du vielleicht AOP ??



  • Das wird nicht mit virtuellen Methoden und dem oben angesprochenen Design Pattern funktionieren. Für sowas benutzt man imho Overloading.



  • Durch mit Hinzufügen von Methoden:

    template <typename T> struct Type2Type
    {
    	typedef T type;
    };
    
    struct Aepfel {};
    struct Haeuser {};
    
    class Algo
    {
    	public:
    
    		template <typename T>
    		void calc()
    		{
    			Step1();
    			Step2(typename Type2Type<T>::type());
    			Step3();
    		}
    
    	private:
    		void Step1() {std::cout << "Step1" << std::endl;}
    		void Step3() {std::cout << "Step3" << std::endl;}
    
                    void Step2(Aepfel)
    		{
    			std::cout << "Aepfel" << std::endl;
    		}
    
    		void Step2(Haeuser)
    		{
    			std::cout << "Haeuser" << std::endl;
    		}
    
    };
    
    int main()
    {
    	Algo a;
    
    	a.calc<Aepfel>();
    }
    


  • @Shade Of Mine: nee das meine ich nicht



  • @Aquae:

    mir ist halt wichtig, dass die Methode Step2 nicht implmentiert wird, sondern das sie von abgeleiteten Klassen implementiert werden können!

    .. wie mache ich das dann?



  • template <typename T1, typename T2, typename T3> struct Type2Type
    {
        typedef T1 type1;
        typedef T2 type2;
        typedef T3 type3;
    };
    

    ... dann für mehrere Übergabeparameter?

    Mfg



  • Hier mit Unterklassen. Trifft vielleicht eher, das was du wolltest?

    template <typename T>
    class Algo
    {
    	public:
    
    		void calc()
    		{
    			Step1();
    			Step2(T());
    			Step3();
    		}
    
    	protected:
    		virtual ~Algo(){}
    
    		virtual void Step2(T)=0;
    
    	private:
    		void Step1() {std::cout << "Step1" << std::endl;}
    		void Step3() {std::cout << "Step3" << std::endl;}
    };
    
    class AlgoInt : public Algo<int>
    {
    	virtual void Step2(int)
    	{
    		std::cout << "Step2 - int" << std::endl;
    	}
    };
    
    int main()
    {
    	AlgoInt a;
    
    	a.calc();
    
    }
    

    Edit: So gesehen, hast du allerdings dann für jeden Typ einen quasi eigenen Algorithmus, der sich nur in Step2 unterscheidet. Wahrscheinlich auch nicht so wünschenswert.



  • Oder noch eine Variante, die jetzt schon von Aquae gepostete wäre aber wohl vorzuziehen.

    template<typename T>
    class Algorithm
    {
      void Compute()
      {
        // ...
        typeSpecific();
      }
    
      void typeSpecific();
    };
    
    template<typename T>
    void Algorithm::typeSpecific()
    {
      // Standardverhalten, in diesem Fall ein Fehler
      throw std::runtime_error("Keine Spezialisierung für Template-Argument-Typ");
    }
    
    // Die konkreten Typabhängigen Methoden werden als Spezialisierung implementiert
    template<>
    void Algorithm<int>::typeSpecific()
    {
      // Verhalten für int
    }
    
    template<>
    void Algorithm<float>::typeSpecific()
    {
      // Verhalten für float
    }
    


  • Wobei ich deine Variante als intuitiver ansehe 🙂



  • Schon Möglich. Du setzt aber Vererbung ein, was ja das eigentliche Verfahren ist, um Verhalten neu zu definieren. Die Absicht von Template-Spezialisierungen ist ja eher, das selbe Verhalten typabhängig (somit evtl. effizienter) zu implementieren.

    Außerdem hat es mit den Spezialisierungen noch einen Nachteil: Wenn im Algorithmus sehr viele Methoden "austauschbar" sein sollen, hat man bei entsprechend vielen Typen sehr schnell hunderte Spezialisierungen.



  • Verrücktwerd .. schrieb:

    @Shade Of Mine: nee das meine ich nicht

    Der Code der hier produziert wird sieht aber ziemlich danach aus.

    Magst du mal beschreiben was du eigentlich machen willst? Und zwar abstrakt?



  • @Aquae:

    genauso habe ich mir das vorgestellt.
    der Algorithmus (bzw Schablone ist mein calc) und der Step2 ist typspezifisch anders, genauso wollte ich das, aber
    bist du sicher das das so auch kompiliert?



  • template<typename T>
    bool TypeSpecificBehaviour(T i)
    {
      // ...
    }
    
    template<typename T>
    int Algorithm(T p1, T p2, TypeSpecificBehaviour<T> step2)
    {
      // ...
      step2();
      // ...
    }
    

    Ich glaube Shade Of Mine meint so etwas. Hat natürlich den Vorteil, dass du die typspezifischen Funktionen mischen kannst und sie nicht fest in abgeleitete Klassen verdrahtest.



  • @Shade Of Mine:

    Ich möchte einen Algorithmus entwerfen der abhängig vom Typ, innerhalb ein teilweise anderes Verhalten aufweist. Weiterhin sollen eben andere Typen diesen Algorithmus verwenden können, dadurch, dass diese Verhalten implmenetiert wird.



  • Verrücktwerd .. schrieb:

    Ich möchte einen Algorithmus entwerfen der abhängig vom Typ, innerhalb ein teilweise anderes Verhalten aufweist. Weiterhin sollen eben andere Typen diesen Algorithmus verwenden können, dadurch, dass diese Verhalten implmenetiert wird.

    std::sort erfüllt genau diese anforderungen.

    ich kann sort für alle typen und container aufrufen die die minimalen anforderungen erfüllen (sprich: das minimal notwendige verhalten implementieren)



  • Multiple markers at this line
    - in diesem Zusammenhang
    - Variable »a« kann nicht als vom abstrakten Typ »AlgoInt« deklariert werden
    

    ist meine Fehlermeldung, was mach ich noch falsch?

    Mfg



  • .. erhalte ich bei der Implmentierung dieser Variante:

    template <typename T>
    class Algo
    {
        public:
    
            void calc()
            {
                Step1();
                Step2(T());
                Step3();
            }
    
        protected:
            virtual ~Algo(){}
    
            virtual void Step2(T)=0;
    
        private:
            void Step1() {std::cout << "Step1" << std::endl;}
            void Step3() {std::cout << "Step3" << std::endl;}
    };
    
    class AlgoInt : public Algo<int>
    {
        virtual void Step2(int)
        {
            std::cout << "Step2 - int" << std::endl;
        }
    };
    
    int main()
    {
        AlgoInt a;
    
        a.calc();
    
    }
    

Anmelden zum Antworten