Template Spezialisierung für Memberfunction



  • jap



  • Firefighter schrieb:

    Wenn jemand jetzt aber für seine Klasse den operator>> überlädt könnte er dafür ja auch meine Funktion nutzen und diese Spezialfälle kann ich jetzt nich abdecken.

    Warum nicht? Ich dachte, dein Code sollte generisch sein, immerhin verwendet er Templates.

    Natürlich könntest du die Generizität noch erhöhen, wenn du Default-Konstruierbarkeit und Kopierbarkeit nicht als Bedingungen festlegen würdest.



  • Ok, dann hab ich noch eine letzte Frage.

    Wir haben ja vorhin den extra Typen "Type2Type" eingefügt um das Problem mit den eventuell nicht konstruierbaren Typen zu umgehen.

    Den brauch ich ja rein technisch gesehen jetzt nicht mehr? Weil ich ja jetzt in der read-Methode eh wieder T object mache und mir das Problem so wieder ins Haus hole oder nicht?



  • Firefighter schrieb:

    Wir haben ja vorhin den extra Typen "Type2Type" eingefügt um das Problem mit den eventuell nicht konstruierbaren Typen zu umgehen.

    Ja, aber auch um von Funktionstemplate-Spezialisierungen wegzukommen. Wenn du keine Spezialisierungen hast, kannst du auch ein ganz normales Template verwenden.

    Zur Default-Konstruierbarkeit habe ich oben noch etwas gesagt. Hängt halt davon ab, wie generisch dein Code sein soll.



  • Nexus schrieb:

    Zur Default-Konstruierbarkeit habe ich oben noch etwas gesagt. Hängt halt davon ab, wie generisch dein Code sein soll.

    Stimmt, grad gelesen. Ich würde es gerne nicht als Bedingung angeben, aber gibt es in C++ Templates solche Constraints wie C# Generics? Ich weiß es grad nicht.

    Wobei mir grad einfällt, ein Defaultctor wäre schon ne feine Sache und als zweite Bedingung nen Überladenen >> Operator wäre auch ganz fein, aber wie gesagt, wie kann ich das definieren?



  • Firefighter schrieb:

    Wobei mir grad einfällt, ein Defaultctor wäre schon ne feine Sache und als zweite Bedingung nen Überladenen >> Operator wäre auch ganz fein, aber wie gesagt, wie kann ich das definieren?

    dokumentiers. wenn die Operationen fehlen, wird der Compiler schon meckern. Mehr geht nicht.



  • Firefighter schrieb:

    Stimmt, grad gelesen. Ich würde es gerne nicht als Bedingung angeben, aber gibt es in C++ Templates solche Constraints wie C# Generics?

    Keine Ahnung wie das in C# genau aussieht, aber du hast in C++ Type-Traits. Concepts waren auch mal eine Diskussion, aber die kommen vorerst noch nicht in die Sprache.

    Firefighter schrieb:

    Wobei mir grad einfällt, ein Defaultctor wäre schon ne feine Sache und als zweite Bedingung nen Überladenen >> Operator wäre auch ganz fein, aber wie gesagt, wie kann ich das definieren?

    Du musst das gar nicht explizit definieren. Code, der die Anforderungen nicht erfüllt, kompiliert nicht.



  • Nexus schrieb:

    Du musst das gar nicht explizit definieren. Code, der die Anforderungen nicht erfüllt, kompiliert nicht.

    Vollkommen korrekt, ganz vergessen. Gut dann nehm ich das Type2Type struct jetzt raus und lass T als Parameter bei der readImpl.



  • Wenn du eh nur einen generischen Fall hast, kannst du readImpl() auch gleich rausschmeissen und direkt read() verwenden.



  • Joa schon, ok ich dank euch fürs erste. 🙂



  • Wollte nochmal die ganze bisherige Lösung präsentieren.
    Um ehrlich zu sein gefällt die mir gar nicht. Fühl mich nich gut beim anschauen der Lösung 😃 Habt ihr noch anmerkungen?

    class Input
    {
    	private:
    		Input(){}
    
    		template<class T>
    		static void getInput(T& object)
    		{
    			std::ios_base::iostate state;
    
    			while(!(std::cin>>object))
    			{
    				std::cout<<"Wrong format, please try again!"<<std::endl;
    				std::cin.clear();
    				std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
    			}
    		}
    	public:
    		template<class T>
    		static T read()
    		{
    			T object;
    			getInput(object);
    			return object;
    		}
    
    		static int read(int lowerBound, int upperBound)
    		{
    			if(lowerBound > upperBound)
    				std::swap(lowerBound,upperBound);
    
    			int object;
    			getInput(object);
    			while(object < lowerBound || object > upperBound)
    			{
    
    				std::cout<<"The value does fall not in the expected range!("<<lowerBound<<"-"<<upperBound<<")"<<std::endl;
    				getInput(object);
    			}
    
    			return object;
    		}
    
    };
    


  • Ist eigentlich soweit in ordnung. die state variable kannste entfernen, benutzt du ja nirgendwo. Ich würde das nicht static machen wollen und das Ganze schreit eigentlich danach, daraus freie Funktionen zu machen bzw aus der class Input einen namespace Input zu machen. Wir sind ja nicht in Java :).

    du kannst dir auch überlegen, das zweite Read generischer zu machen, indem du statt int einen beliebigen Typen erlaubst. so kannst du die Funktionen direkt für float, double etc verwenden.



  • Was mir gerade aufgefallen ist:

    • Deine Klasse hat keinen Status und nur statische Methoden (abgesehen vom sinnlosen Konstruktor). Du könntest auch einen Namensraum benutzen, allerdings müsstest du dann die privaten Member in einem detail -Namespace verstecken.
    • Die Variable state wird nicht benutzt.
    • Gibt es einen Grund für das Tauschen der Bounds? Wäre es nicht sinnvoller, richtig übergebene Bounds zu fordern und mit assert sicherzustellen? Ich habe grundsätzlich eine gewisse Abneigung gegen Versuche, Logikfehler gerade zu biegen 😉
    • Warum while(object < lowerBound || object > upperBound) ? Wird diese Bedingung jemals true , falls der erste getInput(object) -Aufruf fehlschlägt? Davon abgesehen entspricht die Struktur eher do-while .


  • Man dankt für die Kritik und wird sie umsetzen 🙂

    Das mit dem Namespace klingt gut, werde ich glaube umsetzen.


Anmelden zum Antworten