operator>>



  • Hi Leute
    hab kleine probleme mit operator>>.
    Ich möchte gerne das ich das so schreiben kann:

    int main()
    {
        int zahl;
    
        set a("test1.ini") >> read("a") >> toint() >> zahl;
    
        system("PAUSE");
        return 0;
    }
    

    Die Funktionen read() und toint() sind Funktionen der Klasse set.
    Der Operator >> soll das a. bei a.read() ersetzen.

    Geht sowas überhaupt?

    Gruß
    Gamebuntu


  • Mod

    gamebuntu schrieb:

    Geht sowas überhaupt?

    Nein. Zumindest nicht allgemein ohne ganz viel Handarbeit für jede einzelne Funktion. Mit Makrogefrikkel geht's natürlich, aber das willst du nicht.

    Gegenfrage: Wozu?



  • Man soll so einfach wie möglich meine Funktionen aufrufen können,
    statt das man es so machen muss:

    set a("test1.ini");
        a.read("a");
        zahl = a.toint();
    

    Und ich kann was dabei lernen da ich im Bereich
    Operatoren noch nichts gemacht hab.



  • Zunächst solltest Du auf jeden Fall - allein schon um Verwechslungen zu vermeiden - die Klasse anderes nennen, denn set ist bereits eine Klasse der STL.

    read( ) und toint( ) sind Methoden Deiner Klasse set. Also musst Du sie auch damit zusammen aufrufen, also a.toint( ). "So einfach wie möglich" ist ein Trugschluss, wenn es Dir zwar zwei Zeichen zu schreiben erspart, aber vom Syntax her so kurios würde, dass Du selbst und kein anderer Programmierer auf den ersten Blick sieht, was da überhaupt passiert - und warum es nicht auf die ebenso einfache "normale" Weise passiert.

    Es ist durchaus möglich, Objekte in einen Stream zu hängen. Dazu definiert man die entsprechenden friend-Funktionen operator>>( ) oder operator<<( ) . Bei einem tostring( ) könnte das z.B. sinnvoll sein, um den Inhalt eines Objekts "stringisiert" an einen Stream zu schicken, wenn also z.B. ein Objekt message eine Datenstruktur enthält, Du aber an einen Stream den tatsächlichen XML-String rausgeben willst:

    cout << "Elemente: " << message << endl;
    

    Aber das solltest Du gut überlegen, ob Du das wirklich willst! Meistens macht es mehr Arbeit als Nutzen. Denn ein tostring( ), das ein string zurückgibt, geht genauso.

    ~Edit: Beispiel mit xml-message~



  • Man kann sich schon sowas basteln. Entweder mit eigenen Methodenobjekten oder schon fertig std::function bzw. boost:function . Etwas in der Art:

    class set
    {
    public:
        int toint()
        {
            return 1;
        }
        void read(const std::string& s)
        {
    
        }
    };
    
    template<typename T>
    class set_method
    {
    public:
        virtual T operator()(set& s) const = 0;
    };
    
    class read : public set_method<set&>
    {
        std::string s_;
    public:
        read(const char* s) : s_(s) {}
        set& operator()(set& s) const
        {
            s.read(s_);
            return s;
        }
    };
    
    template<typename T>
    T operator>>(set& s, const set_method<T>& method)
    {
        return method(s);
    }
    
    int operator>>(set& s, std::function<int (set*)> f)
    {
        return f(&s);
    }
    
    int main() 
    {
        set a;
        a >> read("a") >> &set::toint;
    
        return 0;
    }
    

    Allerdings halte ich das auch für vollkommenden Schwachsinn. Kein normaler C++ Programmierer wird auf Anhieb verstehen was in dieser Zeile merkwürdiges passiert. Missbrauche Spachfeatures nicht um ungewöhnliche Syntax zu realisieren.


  • Mod

    gamebuntu schrieb:

    Man soll so einfach wie möglich meine Funktionen aufrufen können,
    statt das man es so machen muss:

    set a("test1.ini");
        a.read("a");
        zahl = a.toint();
    

    Und ich kann was dabei lernen da ich im Bereich
    Operatoren noch nichts gemacht hab.

    Du kannst durchaus so etwas machen:

    zahl= set("test1.ini").read("a").toint();
    

    Dafür musste bloß bei read eine Referenz zurückgeben, genauso wie wenn du den Operator >> selber schreiben würdest.

    Ist aber verpönt, weil unübersichtlich.



  • Ok dann werd ich das wohl lieber lassen sowas zu machen.
    Danke für die Antworten und den Rat sowas nicht zu machen.



  • SeppJ schrieb:

    Ist aber verpönt, weil unübersichtlich.

    Och, bei Fenster-GUI-Kram fände ich Function Chaining manchmal ganz schön:

    Window .setWidth(500) .setVisible(true) .setCloseHandler(foo);
    

  • Mod

    fdfdg schrieb:

    SeppJ schrieb:

    Ist aber verpönt, weil unübersichtlich.

    Och, bei Fenster-GUI-Kram fände ich Function Chaining manchmal ganz schön:

    Window .setWidth(500) .setVisible(true) .setCloseHandler(foo);
    

    Ja, das ist keine allgemeine Regel. Aber etwas wie das hier gewünschte set("test1.ini").read("a").toint(); ist wirklich unschön. Es gibt keinen einleuchtenden Grund, warum eine Funktion namens read eine Referenz auf das Objekt zurückgeben sollte.



  • Templates:

    #include <sstream>
    #include <iostream>
    #include <map>
    
    std::map<std::string, std::string> data;
    
    template<typename Value>
    void get(const std::string& key, Value& val)
    {
    	std::stringstream strm;
    	strm << data[key]; // Wert hier einlesen
    	strm >> val;
    }
    
    template<typename Value>
    void set(const std::string& key, Value val)
    {
    	std::stringstream strm;
    	strm << val;
    
    	data[key] = strm.str();
    }
    
    int main()
    {
    	set("Preis", 13.34);
    	set("Artikel", "USB-Maus");
    
    	double preis;
    	std::string name;
    
    	get("Preis", preis);
    	get("Artikel", name);
    
    	std::cout << name << " : " << preis << " Euro " << std::endl;
    
    	return 0;
    }
    


  • #öä#öä, du verlierst so Typsicherheit. Irgendeine Art der Fehlerbehandlung zur Laufzeit (mindestens Stream-Flags abfragen) würde ich auch einbauen.


Anmelden zum Antworten