"Seltsame" Interpretation eines Ctor-Aufrufs



  • Moin,

    ich stoße gerade auf eine (für mich) "seltsame" Interpretation eines Ctor-Aufrufs. Hier ein Beispiel:

    class A { };
    
    class X {
    public:
      explicit X(const A &a) { }
      void test() const { }
    };
    
    void fehler() {
    
      X x1( ( A() ) );
      x1.test();          // OK
    
      X x2( A() );
      x2.test();          // Fehler
    }
    

    An der gekennzeichneten Stelle erhalte ich von GCC (MinGW, Version 4.4) folgende Fehlermeldung:

    error: request for member 'test' in 'x2', which is of non-class type 'X(A (*)())'

    Offensichtlich wird der Ausdruck in der Zeile darüber als Funktionsdeklaration betrachtet. MSVC (Version 2005) gibt mir eine ähnliche Meldung, also muss ich wohl glauben, dass dieses Verhalten dem Standard entspricht.

    Was ich meine, ist natürlich die Konstruktion eines X mit einem anonymen, default-konstruierten A als Argument. Dies kann ich auch sagen, indem ich um den A-Ausdruck Klammern setze, wie mit x1 gezeigt. Bloß will ich es so nicht sagen und meine auch, dass Ausdrücke wie X x2( A() ); in an anderer Stelle funktioniert haben.

    Habt ihr Kommentare oder Anmerkungen? Übersehe ich etwas?

    Stefan.



  • Nein. Das ist einfach so. Die "Macke" ist unter dem Namen "most vexing parse" bekannt. Die Grammatik ist mehrdeutig. Es könnte sowohl eine Variablendefinition + Konstruktoraufruf sein als auch eine Funktionsdeklaration.

    X x2( A() );
    

    x2 ist eine Funktion mit Rückgabewert X, welche ein Funktionszeiger als Parameter übergeben bekommt, wobei die Funktion, auf die der Zeiger zeigt, keine Parameter bekommt und ein A zurückgibt. Es ist äquivalent zu

    X x2( A(*)() );
    

    aufgrund einer "genialen" Idee der C Entwickler, aus Funktionen in Parameterdeklarationen Funktionszeiger zu machen.

    Mit den Klammern um A() bei

    X x2( (A()) );
    

    kann es dann nur noch eine Variablendefinition + Konstruktoraufruf sein.

    Im Falle einer Mehrdeutigkeit hat die Funktionsdeklaration Vorrang.

    In C++0x wird man noch geschweifte Klammern für die Initialisierung benutzen können:

    X x2{ A() };
    

    Gruß,
    SP



  • Tja, manchmal ist C++ wirklich nicht intuitiv. Von "most vexing parse" hatte ich noch nicht gehört. Man lernt halt nie aus 😉

    Danke, Sebastian, für die Information.

    Stefan.

    P.S.: Aber der Ausdruck mit den geschweiften Klammern sieht doch irgendwie bescheuert aus - oder?



  • DStefan schrieb:

    P.S.: Aber der Ausdruck mit den geschweiften Klammern sieht doch irgendwie bescheuert aus - oder?

    array<int> s(5);//array anlegen mit 5 ints
    array<int> s{5};//array anlegen und die 5 reinstopfen
    

    Nun kenne ich X nicht, um zu sehen, was passender ist.



  • DStefan schrieb:

    P.S.: Aber der Ausdruck mit den geschweiften Klammern sieht doch irgendwie bescheuert aus - oder?

    Ich halte davon auch nichts, aber angeblich soll damit die Initialisierung "vereinheitlicht" werden. Sprich, zwei Schreibweisen T a(v); und T a = v; sind zu wenig. 🙄

    Wo es etwas bringt, ist bei std::initializer_list , ich fände es allerdings gut, wenn das = zwingend da stehen müsste:

    std::vector<int> v = {1,2,3,4};
    

    Aber das auszudehnen auf alle Konstruktoraufrufe ist etwas fragwürdig. Vor allem, da entweder ein Konstruktoraufruf mit mehreren Parametern gemeint ist, oder - wenn ein std::initializer_list -Konstruktor unterstützt wird - dieser aufgerufen wird. Das wird etliche Leute verwirren, aber wirkliche Vorteile hat es meiner Meinung nach sehr wenige.



  • Ich finde es schon dahingehend schlecht, da man noch genauer schauen muß, ob bei einem Konstruktoraufruf nun runde oder geschweifte Klammern stehen (gerade bei volkards's Beispiel mußte ich 5-mal hinschauen, um den Unterschied zu sehen).

    Ich hoffe, daß sich dann wenigstens die Schreibweise mit dem = (so wie Nexus schon geschrieben hat) bei den Programmierern durchsetzen wird (ich sehe dann schon "C++0x obfuscated" auf uns zukommen)...



  • Meine Hoffnung besteht darin, dass noch lange Bücher mit dem alten Standard im Umlauf sind und die meisten Leute sich den "schönen" Stil angewöhnt haben, bevor sie mit den Neuerungen in Kontakt kommen. Wenn wir Glück haben, erreicht die {}-Initialisierung ohne = nicht allzu grosse Beliebtheit. 😉

    Aber traurig bin ich deswegen trotzdem etwas. Die Obfuscation wird sich sicher erhöhen. Einige Leute werden sich besser fühlen, wenn sie von Schleifen auf Lambda-Ausdrücke umsteigen, andere, wenn sie alle Konstruktorsyntaxen wild mischen, wieder andere, wenn sie präventiv alle Membervariablen in der Klassendefinition initialisieren.



  • Nexus schrieb:

    Aber traurig bin ich deswegen trotzdem etwas. Die Obfuscation wird sich sicher erhöhen. Einige Leute werden sich besser fühlen, wenn sie von Schleifen auf Lambda-Ausdrücke umsteigen, andere, wenn sie alle Konstruktorsyntaxen wild mischen, wieder andere, wenn sie präventiv alle Membervariablen in der Klassendefinition initialisieren.

    Ich habe den Eindruck, daß ich da nicht mische, sondern endlich trenne, was getrennt gehört. Das = sehe ich da nicht, weil ich Initialisiere und nicht zuweise, aber da könnte ich mir vorstellen, mir es anzugewöhnen.
    Aber Warner wie Du werden öfter angehört werden und vielleicht bildet sich ja eine Splittersekte, die versucht, lesbaren C++-Code zu schreiben.



  • War das jetzt Sarkasmus von dir, volkard?



  • Nexus schrieb:

    Ich halte davon auch nichts, aber angeblich soll damit die Initialisierung "vereinheitlicht" werden. [...]
    🙄

    Ich bin auch relativ skeptisch. Eine "Vereinheitlichung" sehe ich nur darin, dass man endlich vector<int> wie Arrays initialisieren kann (was mir aber ehrlich gesagt auch nicht fehlte bisher). Aber man hat gleich versucht mehrere Dinge auf einmal mit den geschweiften Klammern zu erledigen. Zum Beispiel erlaubt die Initialisierung keine "narrowing conversions". Also

    int k { 123L };
    int m { 3.14 };
    

    wird beides nicht kompilieren, soweit ich das verstanden habe. Wie das Verhalten jetzt "uniform" sein soll, weiß ich nicht.

    Ich verteufel die neue Initialisierungssyntax und std::initializer_list aber noch nicht. Vielleicht wird ja irgendwann der Groschen bei mir fallen. Vielleicht gibt es ein klares Konzept, was ich nur bisher noch nicht erkannt habe.

    Gruß,
    SP



  • Mir macht die Entwicklung von C++ schon etwas Sorgen. Ich meine, C++ ist jetzt schon genügend kompliziert und wird es erst recht durch die wichtigen neuen Sprachmittel, die komplett neue Möglichkeiten schaffen. Dass man jetzt noch für grundlegendste Dinge wie Initialisierung Alternativen einführt... Naja, ich weiss nicht. Verwirrung wird mit Sicherheit entstehen - ob sie das wert ist, wird sich zeigen. Die Einarbeitungszeit in die Sprache wird sich dank solcher Neuerungen aber noch einmal erhöhen, und ich befürchte, für einige (vor allem neue) Anwendungen wird diese Tatsache durch die Vorteile der Wahl von C++ nicht mehr kompensiert.

    Wir können sowieso nur hoffen, dass wir nützliche Aspekte zum Teil übersehen und die Dinge einen guten Lauf nehmen. Und Innovationen, die sich mit Sicherheit positiv bewähren, bietet der neue Standard schliesslich auch nicht wenige.



  • Naja, immer ein wenig auf dem Teppich bleiben. Nur weil C++0x das schreiben von "noch mehr" "obfuscated code" ermöglicht, resp. erleichtert, heißt das nicht, dass sämtliche Programmierer aufspringen und sich absolut kruden und unleserlichen Programmierstil möglichst schnell angewöhnen werden. Wenn einmal ein sinnvoller Einsatzzweck für solche Dinge besteht können sie bestehende Lösungen bestimmt vereinfachen, werden aber im Fall des Nichtgebrauchs nichts verkomplizieren - hoffe ich.
    Aber du hast recht, es wird dadurch nicht leichter, die Sprache zu durchschauen, und einige Jährchen nach der Entwicklung einer Sprache über die Initialisierung von Variablen nachzudenken erscheint nicht all zu sinnvoll.



  • Die Einarbeitungszeit in die Sprache wird sich dank solcher Neuerungen aber noch einmal erhöhen

    sehe ich auch so.
    wobei die einarbeitungszeit für C++ sowieso schon immens ist.
    die paar neuen features die wirklich für die breite masse relevant sind, machen da glaube ich nichtmehr so viel aus.
    und *alles* muss otto-normal-programmierer nicht können/wissen.


Anmelden zum Antworten