Simpelster Code funktioniert nicht so wie er soll


  • Administrator

    Naja, ist ja nun im neuen Standard "gelöst":

    int i{1};
    
    void foo()
    {
      MyClass object{};
      std::complex<double> c{1.0, 2.0};
    }
    

    Grüssli



  • Nexus schrieb:

    drakon schrieb:

    Ich bin mir nicht mehr sicher, wie die Compilermeldung aussieht, aber IIRC nicht sehr hilfreich

    Doch, ziemlich hilfreich. 🙂

    MSVC++ Ausgabe schrieb:

    'MyClass var(void)': Funktion mit Prototyp wurde nicht aufgerufen (war eine Variablendefinition gemeint?)

    Bei welchem Code?
    Ich geb dir mal ein paar Beispiele, wie es aussehn könnte:

    int foo ();
    //...
    std::cout << foo;
    

    error LNK2001: unresolved external symbol "int __cdecl foo(void)" (?foo@@YAHXZ)

    Nicht sehr hilfreich.

    int foo ();
    //...
    foo = 2;
    

    error C2659: '=' : function as left operand

    Nicht sehr hilfreich.

    std::vector<int> foo ();
    //...
    foo.push_back ( 2 );
    

    error C2228: left of '.push' must have class/struct/union

    Nicht sehr hilfreich.

    Man kann sicher noch viel mehr Beispiele mit viel kryptischeren Fehlermeldungen bringen.
    Und das sind Sachen, die immer mal wieder passieren. In der Tat bin ich auf diesen Thread zurückgekommen, weil mir 3. (ja, ich gebs zu) eben gerade passiert ist und ich mich an diese Unterhaltung erinnert habe.



  • Hm, du hast Recht. Ich habe nur ein kurzes Beispiel ausprobiert, bei dem die "Variable" nicht verwendet wurde.

    Ja, natürlich ist es mühsam, dass Konstruktoraufrufe und Funktionsdeklarationen so eine ähnliche Syntax haben. Aber das trifft nicht nur auf Defaultkonstruktoren zu.

    struct MyClass
    {
    	MyClass(double var);
    };
    
    int main()
    {
    	int a;
    	MyClass b(double(a)); // Funktionsdeklaration	
    }
    

    Doch schauen wir uns nochmals die Alternativen an.

    • Solche Ausdrücke immer als Konstruktoraufrufe interpretieren. Scheint auf den ersten Blick praktisch, aber hat den Nachteil, dass der genau gleiche Ausdruck auf globaler Ebene als Funktionsdeklaration interpretiert wird. Dort wiederum sind solche Konstruktoraufrufe nicht möglich. Also hat man eine neue Inkonsistenz, zusätzlich zum Nachteil des folgenden Punkts.
    • Lokale Funktionsdeklarationen verbieten, bei jener Syntax einen Compilerfehler erzeugen. Der Nachteil besteht im fehlenden Feature, welches jedoch – wie bereits gezeigt – in gewissen Situationen nützlich sein kann. Der Vorteil besteht im Compilerfehler. Jedoch ist das momentan schon fast immer der Fall (wenn auch weniger aussagekräftig, was aber hauptsächlich für Anfänger ein Problem darstellt). Die Verwirrung bei Anfängern bleibt hingegen bestehen, weil für diese nicht klar ersichtlich ist, was an dem "Konstruktoraufruf" falsch ist. Schliesslich ist es ebenso eine Inkonsistenz, dass MyClass(arg) und MyClass obj(arg) Konstruktoraufrufe sind, während MyClass() und MyClass obj() unterschiedlich behandelt werden.

    Man behebt also Probleme und schafft sich gleichzeitig neue.

    Und wieso diese ganze Diskussion? Wie oft macht man diesen Fehler? Ich sehe das ähnlich wie bei if (a = 3) . Es gibt Leute, die wählen hier den hässlichen Weg if (3 == a) , um sicherzugehen, obwohl dieser Fehler sehr selten auftritt. Eigentlich ist if (a = 3) sogar schlimmer, weil der Code kompiliert und erst zur Laufzeit merkwürdiges Verhalten erzeugt.

    Ich meine, mit der Begründung, dass ein Feature von wenigen gekannt oder benutzt wird, könnte man gegen einige Sprachmittel aus C++ vorgehen. Die Verwechslungsgefahr mit Konstruktoren gefällt mir natürlich auch nicht, aber die Alternativen halte ich nicht wirklich für besser. Das C++-Standardkommitee scheint den Status Quo ebenfalls für das kleinere Übel zu halten.



  • Lokale Funktionsdeklarationen verbieten, bei jener Syntax einen Compilerfehler erzeugen. Der Nachteil besteht im fehlenden Feature, welches jedoch – wie bereits gezeigt – in gewissen Situationen nützlich sein kann. Der Vorteil besteht im Compilerfehler. Jedoch ist das momentan schon fast immer der Fall (wenn auch weniger aussagekräftig, was aber hauptsächlich für Anfänger ein Problem darstellt). Die Verwirrung bei Anfängern bleibt hingegen bestehen, weil für diese nicht klar ersichtlich ist, was an dem "Konstruktoraufruf" falsch ist. Schliesslich ist es ebenso eine Inkonsistenz, dass MyClass(arg) und MyClass obj(arg) Konstruktoraufrufe sind, während MyClass() und MyClass obj() unterschiedlich behandelt werden.

    Der Vorteil läge darin, dass die Fehlermeldung eindeutig und immer die gleiche wäre. Da würde dann stehen, dass das einfach nicht geht und wahrscheinlich die Klammern zu viel sind. Da muss dann auch ein Anfänger nicht mehr wirklich nachdenken, was er ändern muss und wo der Fehler ist. (Bei meinen obigen Beispielen ist der Fehler schwerer zu erkennen..)

    Und mir ist auch der Sinn dieses "Features" nicht ganz klar. Alles, was man damit machen kann kann man über namespaces viel besser machen.



  • Vielleicht sollte man sich auf einen Kompromiss einigen und in dem Fall einfach eine Warnung ausgeben.


Anmelden zum Antworten