Gibt es ein "with" in C++


  • Mod

    Mit C++11 gibt es auch verallgemeinerte Initialisierungslisten:

    struct foo
    {
      int a;
      double b;
      const char* c;
    };
    
    int main()
    {
      foo f = {2, 2.2, "Hallo"};   // Geht schon immer
      f = {1, 1.1, "Welt!"};       // C++11
    }
    


  • Nein, und IMHO sollte es das auch nicht geben, weil es der Idee der Kapselung zuwider läuft.

    In C++ gibt es aber Konstruktoren mit Initialisierungsliste:

    struct Eigenschaft {
        Eigenschaft( int fontSize, bool bold, bool italic )
            : FontSize( fontSize )
            , Bold( bold )
            , Italic( italic )
        {}
        int FontSize;
        bool Bold;
        bool Italic;
    };
    

    Vorteil: Du kannst kein Attribut vergessen!

    Gruß
    Werner


  • Mod

    SeppJ schrieb:

    f = {1, 1.1, "Welt!"};       // C++11
    

    Hab ich was verpasst? Ich bin ziemlich sicher, dass das nicht geht. iirc brauchst du hierfür einen entsprechenden Zuweisungsoperator, der einen geeigneten initializer_list-Parameter hat.


  • Mod

    camper schrieb:

    SeppJ schrieb:

    f = {1, 1.1, "Welt!"};       // C++11
    

    Hab ich was verpasst? Ich bin ziemlich sicher, dass das nicht geht. iirc brauchst du hierfür einen entsprechenden Zuweisungsoperator, der einen geeigneten initializer_list-Parameter hat.

    Zumindest der GCC frisst das mit -pedantic, dem habe ich das einfach mal geglaubt.



  • #define with(x) \
        for(bool once = true; once; once = false) \
            for(auto& _ = x; once;)
    

    ->

    with(foo)
    {
        _.bar = 123;
        _.baz = 456;
    }
    


  • camper schrieb:

    SeppJ schrieb:

    f = {1, 1.1, "Welt!"};       // C++11
    

    Hab ich was verpasst? Ich bin ziemlich sicher, dass das nicht geht. iirc brauchst du hierfür einen entsprechenden Zuweisungsoperator, der einen geeigneten initializer_list-Parameter hat.

    Wieso? Es gibt doch schon einen Zuweisungsoperator

    foo& foo::operator=(foo const&);
    

    und den Parameter des Zuweisungsoperators kann ich per "copy list initialization" erzeugen, genauso wie hier:

    foo param = {1, 1.1, "Welt"};
    

    ... dachte ich ...


  • Mod

    Ich bin nicht so ganz sicher, auf die Schnelle finde ich

    5.17 Assignment and compound assignment operators [expr.ass]
    ...
    9 A braced-init-list may appear on the right-hand side of
    — an assignment to a scalar, in which case the initializer list shall have at most a single element. The
    meaning of x={v}, where T is the scalar type of the expression x, is that of x=T(v) except that no
    narrowing conversion (8.5.4) is allowed. The meaning of x={} is x=T().
    — an assignment defined by a user-defined assignment operator, in which case the initializer list is passed
    as the argument to the operator function.
    [ Example:
    complex<double> z;
    z = { 1,2 }; // meaning z.operator=({1,2})
    z += { 1, 2 }; // meaning z.operator+=({1,2})
    int a, b;
    a = b = { 1 }; // meaning a=b=1;
    a = { 1 } = b; // syntax error
    —end example ]

    Evtl. sollte man mal schauen, was clang an der Stelle tut, gcc machte ja bei list-Initialisierung bisher noch nicht alles richtig.



  • Ich finde das, was du zitiert hast, unmissverständlich.

    complex<double> c;
    c = {2,3};
    

    ist demnach nichts besonderes, nur äquivalent zu

    c.operator=({2,3});
    

    was eine copy-list-initialization des operator= Parameters vom Typ complex<double> darstellt.


  • Mod

    krümelkacker schrieb:

    Ich finde das, was du zitiert hast, unmissverständlich.

    complex<double> c;
    c = {2,3};
    

    ist demnach nichts besonderes, nur äquivalent zu

    c.operator=({2,3});
    

    was eine copy-list-initialization des operator= Parameters vom Typ complex<double> darstellt.

    Richtig.
    Ein Aggregat wie in SeppJs Beispiel hat aber keinen user-defined assignment operator, std::complex dagegen schon (warum eigentlich? doch nicht etwa dieses Problems wegen?)



  • Jetzt ist die Frage: Kompiliert g++ es einfach nur, oder tut es auch noch das Richtige?



  • camper schrieb:

    user-defined assignment operator

    Uppsi! Ich kann mir vorstellen, dass diese Einschränkung keine Absicht war.


  • Mod

    Der entsprechende Text findet sich so formuliert erstmals in n2640 und taucht im Draft n2691 auf.
    Obwohl da viel Text steht, wird offenbar nicht explizit auf den Zuweisungsoperator eingegangen. Wahrscheinlich muss man dafür auch noch die früheren Entwürfe anschauen.



  • Werner Salomon schrieb:

    Nein, und IMHO sollte es das auch nicht geben, weil es der Idee der Kapselung zuwider läuft.

    Warum läuft es der Idee der Kapselung zuwieder, wenn kurzfristig öffentliche Methoden in einem markierten, lokalen Namensraum, ohne explizite Objektnennung aufgerufen werden können?

    Was ist der Unterschied zwischen:

    a.foo();
    a.bar();
    

    und

    with(a){
    .foo();
    .bar();
    }
    

    Oder hebst du nur auf dem Beispiel ab (in dem Fall wäre deine Aussage auch nicht völlig unproblematisch)? Dann hat aber ca 90% des Threads nichts mit der Frage zu tun 🙂



  • Kellerautomat schrieb:

    #define with(x) \
        for(bool once = true; once; once = false) \
            for(auto& _ = x; once;)
    

    ->

    with(foo)
    {
        _.bar = 123;
        _.baz = 456;
    }
    

    Es gab eine bessere Variante (ungetestet)

    #define with(x) for(auto &_=(x);true;break)
    

    Ein Grundsatz der OOP und der damit verbundenen Kapselung ist das es dem Programmierer einer Klasse möglich ist, auf Falschzustände zu reagieren. Eine struct kann man belegen wie man möchte, genauso muss man nichts initialisieren. Eine Klasse hingegen sollte ständig ihren Zustand überprüfen können um "codenah" einen Fehler zu melden. Deshalb lieber class ohne public member variablen(stattdessen setter und getter mit Parameterüberprüfung), keine structs und somit sind auch keine with-listen nötig außer vielleicht:

    with(object)
    {
    _.update();
    _.copy();
    _.draw();
    }
    

    Diese Kurzschreibweisen haben sind in C++ eigentlich nie bewährt. Schau Dir mal Perl-Code an! Kurz und knackig, aber wer den nicht kommentiert kennt sich bald nicht mehr aus. In C++ kommt man dafür mit weniger Kommentaren aus, also Arbeit ist die Gleiche!



  • PhilippHToner schrieb:

    Es gab eine bessere Variante (ungetestet)

    #define with(x) for(auto &_=(x);true;break)
    

    Das for-Update muss ein Ausdruck sein.



  • Bashar schrieb:

    PhilippHToner schrieb:

    Es gab eine bessere Variante (ungetestet)

    #define with(x) for(auto &_=(x);true;break)
    

    Das for-Update muss ein Ausdruck sein.

    Sorry stimmt, es war eine Variant, die gleichzeitig einen Pointer überprüft hat, also es gehen nur Pointer. Ich fand die Variante so eigentlich extrem brauchbar.

    #define with(x) if(auto _=(x))
    
    class A
    {
    public:
    	void foo(){}
    };
    
    int main()
    {
    	A *a = new A;
    	with(a)
    	{
    		_->foo();
    		delete _;
    	}
    }
    

Anmelden zum Antworten