Operator Überladung - Automatisch generieren lassen?



  • Nathan schrieb:

    bool operator!=(const T &a, const T &b) = default;
    // Compiler generiert:
    {
      return !(a == b);
    }
    

    Das wäre schon cool.

    Dann wohl eher:

    bool operator!=(const T &a, const T &b) = default;
    // Compiler generiert:
    {
      return !static_cast<bool>(a == b);
    }
    
    // oder meinetwegen:
    bool operator!=(const T &a, const T &b) = default;
    // <=>
    auto operator!= (T const& Lhs, T const& Rhs) -> decltype(!(Lhs == Rhs))
    {
        return !(Lhs == Rhs);
    }
    


  • Nathan schrieb:

    Zu 2: Schau dir boost operators an.

    Hm Ok, werd ich mir mal anschauen, danke. Wobei ich ja gerne auf boost verzichten würde (außerdem sieht das wieder sehr komplex aus für etwas eigentlich sehr simples...).

    Nathan schrieb:

    Zu 1: Ja, es wäre richtig cool wenn der Compiler Operatoren automatisch generieren lassen könnte. C++11 bietet sogar die Syntax dafür:

    Das wäre wirklich schön, ist sowas für die Zukunft geplant?

    asfdlol schrieb:

    Dann wohl eher:

    bool operator!=(const T &a, const T &b) = default;
    // Compiler generiert:
    {
      return !static_cast<bool>(a == b);
    }
    
    // oder meinetwegen:
    bool operator!=(const T &a, const T &b) = default;
    // <=>
    auto operator!= (T const& Lhs, T const& Rhs) -> decltype(!(Lhs == Rhs))
    {
        return !(Lhs == Rhs);
    }
    

    Wozu soll man hier noch den cast zu bool brauchen? (a == b) gibt doch schon ein bool zurück, wozu soll das dann nochmal gecastet werden?





  • manni66 schrieb:

    http://en.cppreference.com/w/cpp/utility/rel_ops/operator_cmp

    Ich hab einfach nur operator== als Beispiel genommen, weil ich keine Lust hab, mir die effizienteste Implementierung von operator+ mithilfe von operator+= zu überlegen und aufzuschreiben...
    Natürlich gibt es rel_ops, aber genauso wie boost.operators ist das nicht ganz dasgleiche wie ein language feature.

    @asdflol:
    Man braucht kein Cast oder decltype. Die = default Variante erwartet, dass eine Funktion mit derselben Signatur existiert, ansonsten ist das ein Fehler. Templates zählen auch nicht, das würde evtl. zu ungewollten Effekten führen.



  • manni66 schrieb:

    http://en.cppreference.com/w/cpp/utility/rel_ops/operator_cmp

    rel_ops ist ein komplettes Fehldesign, besser nicht verwenden.

    Boost hat den besseren Ansatz, man kann ihn auch leicht selber nachprogrammieren.



  • big_flops schrieb:

    rel_ops ist ein komplettes Fehldesign, besser nicht verwenden.

    Hm, warum denn? Was können für Probleme mit der Verwendung von rel_ops auftreten?



  • Da es sich um Templates handelt, werden die Operatoren für viel mehr Überladungen herangezogen, als du willst.



  • happystudent schrieb:

    Wozu soll man hier noch den cast zu bool brauchen? (a == b) gibt doch schon ein bool zurück, wozu soll das dann nochmal gecastet werden?

    Wenn man so etwas als Sprachfeature anbietet, dann soll es so allgemein wie möglich sein. Der ! -Operator ist überladbar und der == -Operator muss nicht notwendigerweise bool zurückgeben.



  • spoler schrieb:

    Da es sich um Templates handelt, werden die Operatoren für viel mehr Überladungen herangezogen, als du willst.

    Welche sind das?



  • asfdlol schrieb:

    Wenn man so etwas als Sprachfeature anbietet, dann soll es so allgemein wie möglich sein. Der ! -Operator ist überladbar und der == -Operator muss nicht notwendigerweise bool zurückgeben.

    Versteh ich nicht. Der ! -Operator ist überladbar, ja, aber doch nicht bezüglich des Rückgabewertes? Also wenn ich schreibe:

    bool operator==(MyClass const &lhs, MyClass const &rhs)
    {
        return lhs.value == rhs.value; // Irgendwas
    }
    
    bool operator!=(MyClass const &lhs, MyClass const &rhs)
    {
        return !(lhs == rhs);
    }
    

    dann ist die Signatur für MyClass ja schon "blockiert". Also ich kann dann eh keinen Overload für den !=Operator schreiben, der zwei MyClass Typen als Argument nimmt.

    Und wenn der ==operator tasächlich nicht ein bool zurückgibt (was ich aber schon ziemlich fragwürdig finden würde), warum sollte dann der daraus default-hergeleitete !=operator trotzdem (per erzwungenem cast) bool zurückgeben und nicht das selbe wie derjenige ==operator der für die default Herleitung hinzugezogen wurde?



  • happystudent schrieb:

    Versteh ich nicht. Der ! -Operator ist überladbar, ja, aber doch nicht bezüglich des Rückgabewertes?

    Doch?

    happystudent schrieb:

    Also wenn ich schreibe: [...] dann ist die Signatur für MyClass ja schon "blockiert". Also ich kann dann eh keinen Overload für den !=Operator schreiben, der zwei MyClass Typen als Argument nimmt.

    Richtig, und weiter?

    happystudent schrieb:

    Und wenn der ==operator tasächlich nicht ein bool zurückgibt (was ich aber schon ziemlich fragwürdig finden würde), warum sollte dann der daraus default-hergeleitete !=operator trotzdem (per erzwungenem cast) bool zurückgeben und nicht das selbe wie derjenige ==operator der für die default Herleitung hinzugezogen wurde?

    Weil der für den Rückgabewert vom == -Operator überladene ! -Operator möglicherweise semantisch etwas Anderes ausdrückt als der ! -Operator bei bool s.



  • happystudent schrieb:

    Und wenn der ==operator tasächlich nicht ein bool zurückgibt (was ich aber schon ziemlich fragwürdig finden würde), warum sollte dann der daraus default-hergeleitete !=operator trotzdem (per erzwungenem cast) bool zurückgeben und nicht das selbe wie derjenige ==operator der für die default Herleitung hinzugezogen wurde?

    Nehmen wir einfach mal das hier an:

    [code="cpp"]
    int operator==(MyClass const &lhs, MyClass const &rhs)
    {
        return lhs.value - rhs.value;
    }
    
    auto operator!=(MyClass const &lhs, MyClass const &rhs) = default;
    

    Was sollte der !=-Operator dann zurückgeben? Einen "Nicht"-Int? Oder -(lhs == rhs)? (Was ist in dem Fall mit Vorzeichenlosen Typen?)
    Oder soll tätlich ein boolscher Cast per ! vorgenommen werden?

    Das klingt halt alles sehr willkürlich...



  • Skym0sh0 schrieb:

    Nehmen wir einfach mal das hier an:

    int operator==(MyClass const &lhs, MyClass const &rhs)
    {
        return lhs.value - rhs.value;
    }
    
    auto operator!=(MyClass const &lhs, MyClass const &rhs) = default;
    

    Was sollte der !=-Operator dann zurückgeben? Einen "Nicht"-Int? Oder -(lhs == rhs)? (Was ist in dem Fall mit Vorzeichenlosen Typen?)
    Oder soll tätlich ein boolscher Cast per ! vorgenommen werden?

    Das klingt halt alles sehr willkürlich...

    Welchen Sinn sollte ein operator== haben, der einen int liefert?



  • Imho ein großer Fehler von C++ solch unsinnige Operatorenüberladungen zu erlauben. Erlaubt zwar Spielereien wie Boot.Spirit - aber ist sehr schlechter Stil.



  • asfdlol schrieb:

    happystudent schrieb:

    Versteh ich nicht. Der ! -Operator ist überladbar, ja, aber doch nicht bezüglich des Rückgabewertes?

    Doch?

    Ok, ich dachte du meintest mehrfach überladbar, Missverständnis.

    asfdlol schrieb:

    Weil der für den Rückgabewert vom == -Operator überladene ! -Operator möglicherweise semantisch etwas Anderes ausdrückt als der ! -Operator bei bool s.

    Ja schon, aber dann wärs doch besser eine Warnung zu generieren als das durch einen cast zu verschleiern oder? Halt in etwa wie wenn ich schreibe:

    bool b = 2; // warning C4305: 'initializing' : truncation from 'int' to 'bool'
    

    Skym0sh0 schrieb:

    Nehmen wir einfach mal das hier an:

    [code="cpp"]
    int operator==(MyClass const &lhs, MyClass const &rhs)
    {
        return lhs.value - rhs.value;
    }
    
    auto operator!=(MyClass const &lhs, MyClass const &rhs) = default;
    

    Was sollte der !=-Operator dann zurückgeben? Einen "Nicht"-Int? Oder -(lhs == rhs)? (Was ist in dem Fall mit Vorzeichenlosen Typen?)
    Oder soll tätlich ein boolscher Cast per ! vorgenommen werden?

    Das klingt halt alles sehr willkürlich...

    Hier würde ich eben wie oben beschrieben eine Warnung ausgeben. Wenn der Compiler einfach aus dem operator== einen operator!= mittels !(lhs == rhs) generiert dann ist doch alles eindeutig und nicht willkürlich.

    Wenn man wirklich so exotische Überladungen für diese Operatoren braucht (wie etwa einen int als Rückgabetyp) dann kann (bzw. muss) man sie halt immer noch explizit hinschreiben. Dann kann man sich aber auch nicht drüber beschweren, von daher seh ich das Problem nicht.

    In 99,9% der Fälle will man je eh einen bool als Rückgabetyp. Und in den paar Asnahmefällen schreibt man die entsprechenden Operatoren halt explizit hin.



  • Ethon schrieb:

    Imho ein großer Fehler von C++ solch unsinnige Operatorenüberladungen zu erlauben. Erlaubt zwar Spielereien wie Boot.Spirit - aber ist sehr schlechter Stil.

    rofl



  • Kellerautomat schrieb:

    Ethon schrieb:

    Imho ein großer Fehler von C++ solch unsinnige Operatorenüberladungen zu erlauben. Erlaubt zwar Spielereien wie Boot.Spirit - aber ist sehr schlechter Stil.

    rofl

    Ja weil

    std::string s2;
    std::getline(std::cin, s2);
    
    std::string s1 = "Hallo";
    s1.append(" ");
    s1.append(s2);
    
    std::cout.write(s1).endl();
    

    auch so geil und viel kürzer ist.

    Oder hättest gerne sowas wie in Java, wo keine Operatorenüberladung exitiert, außer bei dem im Sprachkern festgenagelten java.lang.String (was ja wohl eine blöde Ausnahme darstellt)??



  • Hey, ich stimme dir sogar zu, dass die Iostream Operatoren scheisse sind.
    Und trotzdem ist Operator Ueberladung gut so wie sie ist. Fehlen nur noch benutzerdefinierte Operatoren wie in Swift, das waere geil.



  • Kellerautomat schrieb:

    Hey, ich stimme dir sogar zu, dass die Iostream Operatoren scheisse sind.

    Erklär mal...



  • Ich finde Operatoren-Überladung in D ganz gut: http://dlang.org/operatoroverloading.html

    Irgendwo in der Mitte zwischen künstlerischer Freiheit und logischer Semantik.
    Zb. implementiert man die Operatoren <, <=, >, >= indem man eine einzige, strcmp-ähnliche Funktion implementiert - super. 👍

    Das schlimmste ist dass wenn C++-Operatoren sich anders als erwartet verhalten (warum kann ein Multiplikationsoperator nochmal eine Datenbankverbindung zurückgeben und eine Seite auf dem Drucker ausdrucken ?) man sie auch noch schwer findet - oder kapieren IDEs heutzutage bei der Verwendung eines Operators dass das ein überladener Operator ist und führen einen direkt zur Dekleration?

    ---

    Skym0sh0 schrieb:

    Kellerautomat schrieb:

    Ethon schrieb:

    Imho ein großer Fehler von C++ solch unsinnige Operatorenüberladungen zu erlauben. Erlaubt zwar Spielereien wie Boot.Spirit - aber ist sehr schlechter Stil.

    rofl

    Ja weil

    std::string s2;
    std::getline(std::cin, s2);
    
    std::string s1 = "Hallo";
    s1.append(" ");
    s1.append(s2);
    
    std::cout.write(s1).endl();
    

    auch so geil und viel kürzer ist.

    Oder hättest gerne sowas wie in Java, wo keine Operatorenüberladung exitiert, außer bei dem im Sprachkern festgenagelten java.lang.String (was ja wohl eine blöde Ausnahme darstellt)??

    Fände es so schöner:

    cout.writeln("Hallo ", cin.getln());
    

Anmelden zum Antworten