Kleine Umfarge: C++09 oder Ur-C++



  • rüdiger schrieb:

    player424 schrieb:

    Die Lambda-Funktionen z.B. finde ich unnötig. Ich hatte jetzt noch keinen wirklichen Fall, wo sie einen erkennbaren Mehrwert gebracht hätten. Dem Nutzen dieser Spracherweiterung steht dann auch die etwas undurchsichtige Syntax entgegen.

    Bei Lambda-Funktionen finde ich die Syntax nur hässlich. Ansonsten sind sie imho sehr nützlich, da man ja oft mal schnell einen Funktor braucht und derzeit dafür dann irgend wo eine kleine Klasse basteln muss.

    Dass sie nützlich sind steht eigentlich außer Frage. Die Alternativen dazu sind:
    (1) Code des Funktors irgendwo anders ablegen --> zerstört den Lesefluss
    (2) Eventuell kriegt man ein entsprechendes Funktionsobjekt mit std::bind hin. Lesen+Verstehen ist bei dem, was dabei raus kommt, schwieriger.

    Ich denke die Syntax ist auch nur eine Frage der Gewöhnung. Es gefällt mir sogar, dass ich über die "Capture-Clause" steuern kann, was kopiert und was referenziert wird vom "Umfeld". Ich hätte mir allerdings noch ein "move-capture" gewünscht, zB so etwas:

    template<class Fun>
    void exec(Fun fun) {
      fun();
    }
    
    void foobar()
    {
      unique_ptr<int> p (new int);
      *p = 1729;
      exec([-p]{ // <-- kein C++0x, aber so könnte ein "move-capture" aussehen.
        cout << *p << '\n';
      });
    }
    

    auto...

    rüdiger schrieb:

    Es macht in den meisten Situationen den Code sicher leserlicher.
    zB was bei mir öfters im Code vorkommt:

    template<typename Lhs, typename Rhs>
    typename detail::add<Lhs, Rhs>::type
    add(Lhs const &lhs, Rhs const &rhs) {
      ...
    }
    

    wird mit auto imho deutlich lesbarer

    template<typename Lhs, typename Rhs>
    auto add(Lhs const &lhs, Rhs const &rhs) {
      ...
    }
    

    Das wär nett gewesen. Aber Du kannst nicht einfach den return-Typ weglassen. Oder meintest Du

    template<typename Lhs, typename Rhs>
    auto add(Lhs const &lhs, Rhs const &rhs) -> decltype(lhs+rhs) {
      ...
    }
    

    ?

    Die Alternative dazu wäre

    template<typename Lhs, typename Rhs>
    decltype(declval<Lhs const&>()+declval<Rhs const&>())
    add(Lhs const &lhs, Rhs const &rhs) {
      ...
    }
    

    Innerhalb von decltype habe ich lhs durch declal<Lhs const&>() ersetzt. Wir brauchen keine extra detail::add-Klasse schreiben. declval ist dazu da, für decltype-Ausdrücke Objekte herzuzaubern. 🙂

    rüdiger schrieb:

    player424 schrieb:

    Aus der Standardbibliothek hätte man, meiner Meinung nach auch die Klasse für statische Arrays und Tuples auslassen können.

    Was?! Nein! Beides sind imho sehr sinnvolle Klassen, die ich auch regelmäßig benutze.

    Sehe ich auch so.

    kk



  • Die echten Probleme von C++ löst der neue Standard auch nicht, weil er dann nicht mehr kompatibel wäre.



  • rüdiger schrieb:

    wird mit auto imho deutlich lesbarer

    template<typename Lhs, typename Rhs>
    auto add(Lhs const &lhs, Rhs const &rhs) {
      ...
    }
    

    wäre übersichtlicher, geht so aber soweit ich weiss nicht 😉



  • player424 schrieb:

    Die Lambda-Funktionen z.B. finde ich unnötig.

    Du findest den ultimativen Imperativ unnötig?
    🙂


  • Administrator

    player424 schrieb:

    Aber wozu braucht ihr eine Klasse für etwas, dass schon fest in der Sprache eingebaut ist (std::array)?

    std::array und ein C-Array sind zwei grundverschiedene Sachen. Ein C-Array ist äusserst flüchtig und du endest im Nu mit einem Zeiger ohne Informationen über die Grösse des Arrays oder eine sinnvolle Möglichkeit das Array zu kopieren. std::array gibt dir wirklich ein Array mit konstanter Grösse, welches du auch als Array behandeln kannst. Grundsätzlich wird std::array das C Array vollständig ablösen können.

    player424 schrieb:

    Und was die Tuple-Klasse angeht: Mir fallen spontan nur wenige Beispiele ein, bei denen man so etwas brauchen könnte.

    Immer wenn man etwas kurz gruppieren möchte. Das kann für viele Fälle sinnvoll sein, von Rückgabewerte bis hin zu Algorithmen, wo man temporär Dinge zusammenbinden muss. Das praktische ist, man muss nicht immer wieder eine eigene kleine Struktur basteln. Ist grundsätzlich ähnlich wie die Lambda-Ausdrücke, es erleichtert einem das Leben.

    Grüssli



  • Gibts denn auch ne schöne möglichkeit darauf zu zu greifen? das std::get<n> konstruk ist irgendwie ziemlich... groß.



  • Der ganze STL Kram ist allgemein sehr klobig. Schau dir mal std::cout an. Damit etwas tabellarisch auszugeben ist genau so eleganz wie einen essay in den schnee zu pinkeln. Dagegen ist das C typische printf elegant und schlank.



  • Der ganze STL Kram ist allgemein sehr klobig.

    Ist es klobig std::vector<MyClass> zu schreiben und dann ein dynamisches Array von Objekten der Klasse MyClass zu haben?

    Schau dir mal std::cout an.

    std::cout gehört nicht zu Standard Template Library... 🙄

    Damit etwas tabellarisch auszugeben ist genau so eleganz wie einen essay in den schnee zu pinkeln. Dagegen ist das C typische printf elegant und schlank.

    ...und fehleranfällig.



  • Wenn man keine Ahnung hat schrieb:

    ...und fehleranfällig.

    Aber nur wenn man wild castet, das geht in C++ dann wohl auch schief. Wenn man das nicht tut, kann der Compiler die Typen genauso überprüfen wie überall sonst.
    🙂


  • Mod

    mngbd schrieb:

    Wenn man keine Ahnung hat schrieb:

    ...und fehleranfällig.

    Aber nur wenn man wild castet, das geht in C++ dann wohl auch schief. Wenn man das nicht tut, kann der Compiler die Typen genauso überprüfen wie überall sonst.
    🙂

    Dummerweise funktioniert das aber auch nur, weil es eine überschaubare Anzahl von zulässigen Datentypen für printf gibt. In einer Sprache wo eigene Datentypen ganz alltäglich sind, geht das Konzept nicht mehr auf.



  • mngbd schrieb:

    Wenn man keine Ahnung hat schrieb:

    ...und fehleranfällig.

    Aber nur wenn man wild castet, das geht in C++ dann wohl auch schief. Wenn man das nicht tut, kann der Compiler die Typen genauso überprüfen wie überall sonst.
    🙂

    Dann sag mir, wo du hier einen Cast siehst 🙂

    char x = 12;
    
    // ...
    
    printf("%d", x);
    

    Kompiliert, ist aber undefiniert.



  • Das ist nicht undefiniert. Befass dich mal mit integer promotions.



  • Dann versuchs mit

    char x = 12;
    printf("%s", x);
    


  • DerKuchen schrieb:

    Dann versuchs mit

    char x = 12;
    printf("%s", x);
    

    Zumindest der gcc erkennt den Unsinn:

    $ gcc -x c -std=c99 -Wall -
    #include <stdio.h>
    
    int main(void) {
      char x = 12;
      printf("%s", x);
    } 
    <stdin>: In Funktion »main«:
    <stdin>:5: Warnung: format »%s« erwartet Typ »char *«, aber Argument 2 hat Typ »int«
    

    🙂



  • Zumindest der gcc erkennt den Unsinn

    Er erkennt ihn vielleicht, aber er verhindert ihn nicht.
    Der aktuelle MS Compiler gibt übrigens (in der Standardeinstellung) keine Warnung aus.



  • Erkenner schrieb:

    Er erkennt ihn vielleicht, aber er verhindert ihn nicht.

    Was soll er denn noch tun? Die Polizei rufen?

    Erkenner schrieb:

    Der aktuelle MS Compiler gibt übrigens (in der Standardeinstellung) keine Warnung aus.

    Der gcc auch nicht, Archaismus. Vielleicht tut's der MS-Compiler ja, wenn man lieb zu ihm ist. Aber vielleicht auch nicht, MS kann ja C bekanntlich nicht so recht leiden.
    🙂



  • Was soll er denn noch tun? Die Polizei rufen?

    Nein, aber es geht hier um die Nachteile von printf() gegenüber den IOStreams. Letztere sind nämlich typsicher und würden ggf. in so einem Fall gar nicht kompilieren.



  • Jonas OSDever schrieb:

    Ich bin nur der Meinung**,** dass manche neuen Sprachkonzepte schwierig zu handhaben sind und manchmal weniger bringen als sie kosten.

    Was kosten sie denn? Dich eine Installation eines neuen Compilers? Mehr Lernaufwand, weil sie in Teilen der Standardbibliothek verwendet werden, die du sonst sowieso nicht benutzen könntest? Ich werde manche Teile des neuen Standards wahrscheinlich auch kaum gebrauchen, aber das ist für mich kein Problem - dafür können mir z.B. erweiterte Standardbibliothek, Variadic Templates, Initializer Lists, auto/decltype, UTF-Strings und static asserts neue Möglichkeiten eröffnen oder Schreibarbeit sparen.



  • Erkenner schrieb:

    Was soll er denn noch tun? Die Polizei rufen?

    Nein, aber es geht hier um die Nachteile von printf() gegenüber den IOStreams. Letztere sind nämlich typsicher und würden ggf. in so einem Fall gar nicht kompilieren.

    Ja und? Das kannst Du mit beim GCC mit -Wall -Wformat=2 -Werror auch haben. Klar, der C Standard fordert so ein Verhalten nicht ein. Aber das macht ja nichts. Wenn der GCC das anbietet, warum nicht bei der Entwicklung nutzen? Ich würde mich nicht als C Programmierer bezeichnen, aber bei aller Fairness muss man den C Programmierern -- zumindest denen, die einen Compiler einsetzen, der bei solchen Dingen gescheit warnen kann -- nicht mit "Typsicherheit" kommen. Diese "Typsicherheit" ist nicht viel besser als eine Compiler-Warnung.



  • Klasse Argument für printf()...

    Meinst du IOStreams wurde aus Spaß in den Standard aufgenommen?

    Das überzeugendste Argument für IOStreams hat aber SeppJ schon gegeben:

    SeppJ schrieb:

    Dummerweise funktioniert das aber auch nur, weil es eine überschaubare Anzahl von zulässigen Datentypen für printf gibt. In einer Sprache wo eigene Datentypen ganz alltäglich sind, geht das Konzept nicht mehr auf.


Anmelden zum Antworten