C++0x doch ohne Concepts



  • audacia schrieb:

    drakon schrieb:

    Ja, aber ich meinte, dass man es nicht wirklich braucht. Man hat dann halt eine etwas unleserliche Syntax und mehr arbeit, wenn man halt einen Funktor schreiben muss, aber grundsätzlich geht das, was man erreichen will. Keine Frage es ist umständlicher und Mehrarbeit, aber es geht.

    Diese Argumentation führt zwangsläufig zu C zurück. Oder ziehst du eine willkürliche Grenze?

    Das führt noch weiter zurück. 😉 - Nein, nicht willkürlich, aber irgendwo muss eine Balance her. Mir persönlich brächte es mehr, wenn ich eine anständige Lib für Netzwerk an die Hand gelegt bekäme, als eine Lib, die es mir ermöglicht lambda Funktionen zu schreiben. Die Grenze ist natürlich subjektiv und hängt auch ab, in welchem Bereich man vor hat die Features zu nutzen..

    Stell dir das umgekehrte vor. Du hast eine Sprache, die dir etliche Sprachfeatures bietet, jedoch nicht einmal eine Bibliothek für String Verarbeitung bietet. Auch nicht so toll, oder?


  • Administrator

    audacia schrieb:

    drakon schrieb:

    Ja, aber ich meinte, dass man es nicht wirklich braucht. Man hat dann halt eine etwas unleserliche Syntax und mehr arbeit, wenn man halt einen Funktor schreiben muss, aber grundsätzlich geht das, was man erreichen will. Keine Frage es ist umständlicher und Mehrarbeit, aber es geht.

    Diese Argumentation führt zwangsläufig zu C zurück. Oder ziehst du eine willkürliche Grenze?

    Falsch! Diese Argumentation führt zu Assembler zurück. Oder wir geben gleich selber 0 und 1 ein. Mehr brauchen wir ja nicht 🙂
    Es scheint aber ziemlich eindeutig zu sein, dass er hier eine subjektive Grenze zieht.

    Edit: Zu spät, da hat drakon schon selber geantwortet 🙂

    audacia schrieb:

    Bibliothekserweiterungen sind schön und gut, aber real viel zu spät - mittlerweile verwendet ohnehin jeder seinen ganz persönlichen Workaround. Viel wichtiger finde ich die Erweiterung der Sprachmöglichkeiten, also Dinge, die man nicht über externe Bibliotheken nachrüsten kann.

    Ich stimme dir zwar zu, dass man viel zu spät ist, aber trotzdem ist es nützlich. Die alte Software wird bei seinen Workarounds bleiben, die neuen dagegen können endlich auf einen Standard setzen. Vielleicht gibt es ja sogar ein paar alte Softwaresystem, welche wechseln werden 😉

    Ich bin allerdings gespannt, was Boost machen wird. Gibt es da schon eine Aussage von den Entwicklern?

    Grüssli



  • drakon schrieb:

    Stell dir das umgekehrte vor. Du hast eine Sprache, die dir etliche Sprachfeatures bietet, jedoch nicht einmal eine Bibliothek für String Verarbeitung bietet. Auch nicht so toll, oder?

    Nein, aber so ähnlich sieht es bei C++ ja aus. Da C++ aus verschiedenen Gründen dennoch relativ große Marktdurchdringung hat, haben sich eben Alternativbibliotheken gefunden und mehr oder weniger etabliert.

    Dravere schrieb:

    Ich stimme dir zwar zu, dass man viel zu spät ist, aber trotzdem ist es nützlich. Die alte Software wird bei seinen Workarounds bleiben, die neuen dagegen können endlich auf einen Standard setzen. Vielleicht gibt es ja sogar ein paar alte Softwaresystem, welche wechseln werden 😉

    Ja, natürlich ist es nützlich, und ich begrüße außerordentlich, daß die Standardbibliothek mit einer Threading-Library und den anderen vorgeschlagenen praxisorientierten Erweiterungen mal etwas weiter in die reale Welt tritt. Aber all das ist nichts, was es nicht jetzt schon gäbe, nur steht eben "Standard" drauf. Deshalb finde ich Sprachfeatures, die es in C++ noch nicht gibt, bei weitem wichtiger.

    Eine Sprachbibliothek muß die Balance finden zwischen einem Minimalkompromiß, der in vielen Bereichen nur beschränkten praktischen Nutzwert bietet (dem ist die gegenwärtige C++-Standardbibliothek recht nahe) und einer voll ausgestatteten "Featuritis"-Bibliothek (z.B. die Java-Library oder das .NET-Framework), die viel schneller zum Ballast wird, als mancher wahrhaben mag. Einen interessanten und, wie ich finde, sehr attraktiven Mittelweg gehen Rich-Client-Frameworks wie VCL und Qt - aber ob das der richtige Ansatz für die C++-Standardbibliothek wäre, weiß ich nicht so recht.



  • Kann mir mal jemand den Sinn von Rvalue-Referenzen erklären? Irgendwie blicke ich den Thread zur Vorstellung der Rvalues nicht:

    string operator + (string const& a, string const& b)
    {
       string tmp (a);
       tmp += b;
       return tmp;
    }
    
    string a ("this ");
    string b = a + "a" + "b" + "cd";
    

    a + "a" ruft doch nicht operator + (string const& a, string const& b) auf (wieso zur Hölle den konstante Referenzen), sondern operator +(string& a, const char* b)?!
    Und was verschiebt sich dann hier???



  • Ach, das brauchst du net zu checken! im neuen c++ ist so viel mist drin, den man nie braucht. eigene literale braucht z.b. kein schwein, dynamische template-anzahl ist zwar ganz nett, kann man auch 1 mal in 40 jahren gebrauchen 😕
    lambda-funktionen und decltypes sind der allerletzte dreck, dank dieser schreibweise ist man nun endgültig verloren, fremden code je nachvollziehen zu können:

    auto concept Bla <typename A, typename B>
    {
       operator +(A const&, B const&);
    }
    
    template <typename T, typename B, ...Args> requires Bla<T, B>
    auto foo(T& a, B& b, Args&& ... args) -> decltype(a + b) {
       return a + b;
    }
    

    ist doch totaler müll!!! braucht kein mensch!!



  • Hä? schrieb:

    Kann mir mal jemand den Sinn von Rvalue-Referenzen erklären?

    Der Sinn ist mehrfach dokumentiert:
    N2027: A Brief Introduction to Rvalue References
    Rvalue Reference 101

    Hä? schrieb:

    string operator + (string const& a, string const& b)
    {
       string tmp (a);
       tmp += b;
       return tmp;
    }
    
    string a ("this ");
    string b = a + "a" + "b" + "cd";
    

    a + "a" ruft doch nicht operator + (string const& a, string const& b) auf (wieso zur Hölle den konstante Referenzen), sondern operator +(string& a, const char* b)?!

    Ich denke, das Beispiel, was Du zitierst, geht nicht davon aus, dass es einen operator+(string const&, char const*) gibt. Nimm der Einfachheit wegen an, dass "string" eine eigene Klasse ist:

    class string {
      .....
    public:
      string();
      string(char const*);
      string& operator+=(string const& x);
      .....
    };
    

    Nimm weiter an, dass die folgenden operator+ Funktionen die einzigen sind, die auf string arbeiten:

    string operator+(string const& lhs, string const& rhs)
    {
      string tmp;
      tmp.reserve(lhs.length() + rhs.length());
      tmp += lhs;
      tmp += rhs;
      return tmp;
    }
    
    string operator+(string && lhs, string const& rhs)
    {
      lhs += rhs;
      return std::move(lhs);
    }
    

    Wo ist nun das Problem?

    Gruß,
    SP



  • Eggy schrieb:

    Ach, das brauchst du net zu checken! im neuen c++ ist so viel mist drin, den man nie braucht.

    Du machst von vielen C++0x Features indirekt allein durch die Nutzung der Standardbibliothek Gebrauch (std::bind, std::function, std::vector, std::tuple, ...). Sie stopfen das ein oder andere Loch, nachdem sich Bibliotheksentwickler gesehnt haben. Nicht jeder ist Bibliotheksentwickler und muss wissen, wozu die C++0x Sprach-Features gut sind. Dumm-User profitieren also indirekt davon.

    Gruß,
    SP



  • volkard schrieb:

    ich hätte gerne Zugriff auf den Parsebaum und würde ihn frei ummodeln können....

    Kann mir jemand vielleicht kurz erläutern, in welcher Form sich der Zugriff auf den Parserbaum hinsichtlich der Sprachfeatures auswirken würde? Welchen "Mehrwert" hätte man zu erwarten, falls dies gestattet wäre? Ich hab leider nicht allzu viel Ahnung was das Parsen angeht, bin mir also der Auswirkungen nicht ganz bewusst.



  • > std::bind, std::function, std::tuple

    Lol, die braucht man genauso oft^^



  • Eggy schrieb:

    im neuen c++ ist so viel mist drin, den man nie braucht.

    So oder so ähnlich:

    vector<int> vals = { 1, 2, 3, 4, 6 };
    
    auto is_smaller_than_three = [] (int i)->bool
    {
    	return i<3;
    }
    
    vals.erase( remove_if( vals.begin(), vals.end(), is_smaller_than_three ) );
    

    Statt:

    vector<int> vals;
    vals.push_back( 1 );
    vals.push_back( 2 );
    vals.push_back( 3 );
    vals.push_back( 4 );
    vals.push_back( 5 );
    vals.push_back( 6 );
    
    struct IsSmallerThanThree
    {
        bool operator()( int i )
        {
            return i<3;
        }
    };
    
    vals.erase( remove_if( vals.begin(), vals.end(), IsSmallerThanThree() ) );
    


  • Eggy schrieb:

    > std::bind, std::function, std::tuple

    Lol, die braucht man genauso oft^^

    Verwechsel mal nicht "man" und "du"...



  • Beispiel:

    template <class T> swap(T& a, T& b)
        {
            T tmp(a);   // now we have two copies of a
            a = b;      // now we have two copies of b
            b = tmp;    // now we have two copies of tmp (aka a)
        }
    
      // Rvalue:
    
        template <class T> swap(T& a, T& b)
        {
            T tmp(std::move(a));
            a = std::move(b);   
            b = std::move(tmp);
        }
    

    Toll, was ist daran jetzt besser? Wir erstellen immernoch 3 Objekte, selber Verbrauch wie vorher, die Objekte sind dabei höchstens leer nach jedem move 😕 .



  • Hä? schrieb:

    // Rvalue:
        template <class T> swap(T& a, T& b)
        {
            T tmp(std::move(a));
            a = std::move(b);   
            b = std::move(tmp);
        }
    

    Toll, was ist daran jetzt besser? Wir erstellen immernoch 3 Objekte, selber Verbrauch wie vorher, die Objekte sind dabei höchstens leer nach jedem move 😕

    "selber Verbrauch" stimmt nicht. Denk an Klassen, die Resourcen kapseln (wie zB vector). Die Objekte an sich sind klein (3 Pointer zum Beispiel) aber eine Kopieroperation kann trotzdem teuer sein, weil eventuell ein dickes Array (wie bei vector) neu angelegt und kopiert werden muss. Mit

    T tmp(std::move(a));
    

    sagst Du, dass das Kopieren destruktiv bzgl der Quelle sein darf ("move construction" erlaubt). Für Typen, wie vector bedeutet das, dass einfach die Zeiger umgebogen werden können, ohne das Speicher neu angefordert werden muss oder Elemente kopiert werden müssen.

    Gruß,
    SP



  • Hä? schrieb:

    Toll, was ist daran jetzt besser?

    Ich sehe gerade, dass das, was ich geschrieben habe auch in etwa in der Einführung steht:

    This move() gives its target the value of its argument, but is not obliged to preserve the value of its source. So, for a vector, move() could reasonably be expected to leave its argument as a zero-capacity vector to avoid having to copy all the elements. In other words, move is a potentially destructive read.
    [...]
    The first task of rvalue references is to allow us to implement move() without verbosity, or rutime overhead.

    Wer lesen kann ist klar im Vorteil...

    Gruß,
    SP



  • Heißt es dann so: ?

    string b = "xxx";
    string &a = b; // a = b = "xxx"
    string &&c = b; // c = b = a = "xxx"
    string x = c; // x = "xxx", c = "" ?????
    

    Ist am Ende c dann leer oder was ist dann in c?



  • Hä? schrieb:

    Heißt es dann so: ?

    string b = "xxx";
    string &a = b;    // a = b = "xxx"
    string &&c = b;   // c = b = a = "xxx"
    string x = c;     // x = "xxx", c = "" ?????
    

    Ist am Ende c dann leer oder was ist dann in c?

    Die Einführung ist nicht 100% auf den letzten Stand. Die Regeln wurden leicht geändert. Deine 3. Zeile kompiliert nicht mehr. Du kannst keine Lvalues an Rvalue-Referenzen binden. Dave Abrahams's "Rvalue References 101" ist aktueller und sehr ausführlich.

    Zu Deiner Frage: Lies Dir diesen Abschnitt durch.

    Bevor Du die nächste Frage stellst, lies Dave's Artikel 2mal komplett und konzentriert durch. Es steht wirklich alles dort....

    Gruß,
    SP



  • Sebastian Pizer schrieb:

    Bevor Du die nächste Frage stellst, lies Dave's Artikel 2mal komplett und konzentriert durch. Es steht wirklich alles dort....

    Nicht, dass Du mich falsch verstehst: Keiner sagt, dass Rvalue-Referenzen leicht zu verstehen sind. Deswegen frag ruhig, wenn Dir etwas unklar ist. Aber frag nicht, wenn Du einfach nur zu faul zum Lesen bist.



  • Neben den grossen Neuerungen wie Variadic Templates, RValue-Referenzen und Lambda-Ausdrücke finde ich auch viele kleinere Dinge sehr nützlich, zum Beispiel Initialisierungslisten, constexpr , neue enum s und static_assert (wird einige Templatefehlermeldungen sicher auch schon besser lesbar machen).

    Allerdings finde ich, mit der "einheitlichen" Initialisierung haben sie übertrieben. Dass die Initialisierungsliste implizit für Konstruktoraufrufe verwendet werden kann, gefällt mir nicht. So ist nämlich für eine Klasse, die keinen Initialisierungslistenkonstruktor anbietet, Folgendes möglich:

    std::fstream file = {"file.txt", std::ios_base::out};
    

    Beim std::vector hingegen wird hier nicht der Konstruktor aufgerufen, der 4 Elemente mit Startwert 3 setzt, sondern der mit der Initialisierungsliste:

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

    In meinen Augen ist das nicht sehr konsistent. Mir wäre es lieber, man könnte Initialisierungslisten höchstens explizit für Konstruktoraufrufe benutzen (evtl. durch auto oder sowas wie std::construct(std::initializer_list) ).

    Dass man das = in den oberen Fällen auch weglassen kann, halte ich ausserdem für unnötig und zudem auch hässlich, diese Schreibweise werde ich wohl kaum verwenden. Hat die irgendwelche Vorteile? Ich meine:

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

    P.S.:

    Badestrand schrieb:

    So oder so ähnlich: [...] Statt: [...]

    Du hast nicht mal Lambda-Ausdrücke benutzt! Schäm dich! 😃



  • Nexus schrieb:

    P.S.:

    Badestrand schrieb:

    So oder so ähnlich: [...] Statt: [...]

    Du hast nicht mal Lambda-Ausdrücke benutzt! Schäm dich! 😃

    'Türlich hat er nen Lambda-Ausdruck benutzt, bloss nicht inline. Was ich auch etwas komisch finder, aber naja.



  • hustbaer schrieb:

    'Türlich hat er nen Lambda-Ausdruck benutzt, bloss nicht inline. Was ich auch etwas komisch finder, aber naja.

    Stimmt, hab ich beim Überfliegen für eine Funktion gehalten. Und ich würds auch eher inline machen... 😉


Anmelden zum Antworten