C++ vor 10 Jahren



  • bashy schrieb:

    Was ich oft brauche ist von a bis b zählen, aber das geht auch wieder nicht.

    for (int i : range(1, 10)) {} // geht nicht
    

    Natürlich geht das!

    #include <iostream>
    
    struct range
    {
        int min, max;
        range(int a, int b)
        : min(a), max(b) {}
    
        struct iterator
        {
            int value;
    
            iterator(int val)
            : value(val) {}
    
            int operator*()
            {return value;}
    
            bool operator != (iterator other)
            {return other.value !=  value;}
    
            iterator operator++()
            {return ++value;}
        };
    
        iterator begin()
        {return iterator(min);}
    
        iterator end()
        {return iterator(max);}
    };
    
    int main()
    {
        for (auto i : range(1, 10))
            std::cout << i << '\t';
    }
    

    Siehste?



  • seldon schrieb:

    Mal abgesehen davon, dass der idiomatische Weg im Zweifel [...] sein dürfte:

    template<typename A2, typename B2, typename C2>
      triple(A2 &&a2, B2 &&b2, C2 &&c2) // universal references
    

    Eben nicht. Dann geht die Brace-Initialisation nicht mehr, die Stroustrup so mag. Mit std::tuple geht das zwar (da const& Parameter), aber nur auf Kosten einer Kopie der anderen Parameter.

    Nathan schrieb:

    Natürlich geht das!

    Ja, es geht. So mache ich das auch. Aber es dürfte nur von wenigen benutzt werden, weil es nicht in der Standardbibliothek implementiert ist.



  • Nathan schrieb:

    <Code-Bloat>
    

    Das witzige ist, dass das noch lange nicht die Bedingungen für einen Iterator erfüllt. Dazu sind erst noch ein paar hundert Zeilen Boilerplate nötig.



  • Ich habe das mal eben in ein paar Minuten gecodet, um es dir zu zeigen. 🙄



  • seldon schrieb:

    template<typename A2, typename B2, typename C2>
      triple(A2 &&a2, B2 &&b2, C2 &&c2) // universal references!
        : a(std::forward(a2)),
          b(std::forward(b2))
    

    Ein weiterer Indikator dafür, dass C++11 viel zu kompliziert ist. Du müsstest std::forward<A2>(a2) schreiben, sonst ist das forward sinnlos.



  • bashy schrieb:

    Ach meinst du?

    Ja, bestimmt. Man muss Typinferenz aber verhältnismässig einsetzen. Die Verlockung ist gerade für Konsistenz-Fanatiker da, nun überall auto hinzuschreiben. Ich benutze auto hauptsächlich für Iteratoren, und da ist es definitiv übersichtlicher als die ausgeschriebene Version.

    bashy schrieb:

    Das range-based For ist sehr oft unnütz.

    Findest du? Ich finde es extrem nützlich. So nützlich, dass ich mir sogar ein Workaround-Makro für VS 2010 à la BOOST_FOREACH geschrieben habe. In vielen Fällen will ich schlicht etwas für alle Elemente tun, und da ist es perfekt.

    Die Standardalgorithmen sind oft praktisch, aber teilweise muss man sie mit Lambdas oder std::bind() derart zurechtbiegen, dass ein Range-Based For massiv übersichtlicher ist. Ein Index ist nicht umständlicher als wenn du normale Iteratoren verwendest. Elemente überspringen kannst du mit continue .

    bashy schrieb:

    Abgesehen davon ist die Unterstützung noch rudimentär.

    for (int key, std::string const& value : my_map) {} // nicht erlaubt
    

    Ich bezweifle, dass man das jemals einführen wird. Und

    for (auto pair : my_map)
    

    ist schon eine massive Verbesserung zu vorher.

    bashy schrieb:

    Was ich oft brauche ist von a bis b zählen, aber das geht auch wieder nicht.

    for (int i : range(1, 10)) {} // geht nicht
    

    Doch, du musst range() halt einen sinnvollen Typen zurückgeben lassen. Mit vorhandenen Mitteln, dafür ineffizienter:

    std::vector<int> range(int begin, int end)
    {
    	std::vector<int> sequence(end - begin);
    	std::iota(sequence.begin(), sequence.end(), begin);
    
    	return sequence;
    }
    


  • bashy hat schon recht gewissermaßen, C++ ist auch heute noch völlig kaputt. C++17 könnte die schlimmsten Fehler vielleicht fixen indem man das Kompilations(Kompilierungs?)-Model umbaut und den "normalen" Einsatz von Templates schmerzfrei macht, aber das wird den ganzen Ballast einer über 10-20(!) Jahre alten Sprachbasis trotzdem nicht los, weil niemand die "backwards compatibility" deutlich brechen will. Traurigerweise ist C++ trotz all dieser wirklich schrecklichen Fehler immer noch die angenehmste mir bekannte Sprache. 🙄



  • bashy schrieb:

    So mache ich das auch. Aber es dürfte nur von wenigen benutzt werden, weil es nicht in der Standardbibliothek implementiert ist.

    Eben, Ranges sind als Bibliotheksfeature nicht vorhanden. Das hat nichts mit dem Sprachfeature Range-Based For Loop zu tun. Wie dir gezeigt wurde, wäre dieses mächtig genug.

    bashy schrieb:

    Ein weiterer Indikator dafür, dass C++11 viel zu kompliziert ist.

    Neben den "netten" Features bietet C++11 eben vieles, um mehr Möglichkeiten für die generischen Programmierung zu bieten (z.B. Variadic Templates, Perfect Forwarding). Wenn du nicht gerade Boost-Bibliotheken schreibst, wirst du sowas sehr selten einsetzen.

    cooky451 schrieb:

    bashy hat schon recht gewissermaßen, C++ ist auch heute noch völlig kaputt. C++17 könnte die schlimmsten Fehler vielleicht fixen [...], aber das wird den ganzen Ballast einer über 10-20(!) Jahre alten Sprachbasis trotzdem nicht los, weil niemand die "backwards compatibility" deutlich brechen will.

    Das hat schon was. Traurigerweise macht man alles noch schlimmer, wenn man Dinge wie die Uniform Initialization schon derart defekt einführt, dass sie nie mehr geradezubiegen sind.

    Ein rücksichtloser Schnitt wäre das einzige, was die Sprache retten könnte. Wird aber kaum passieren, daher muss langfristig eine andere Sprache her. Am ehesten käme noch D in Frage. Dieser Stackoverflow-Thread beschreibt die Probleme von D, insbesondere im Bezug auf dessen Verbreitung.



  • Nexus schrieb:

    std::vector<int> sequence(end - begin);
    std::iota(sequence.begin(), sequence.end(), begin);
    

    iota ist wohl ein weiteres Beispiel für eine völlig misslungene Funktion. Es macht aus meiner Sicht keinen Sinn, ein Iteratorenpaar anzugeben. Etwas im Stil von copy_n wäre angebrachter gewesen. Oder noch besser ein Iterator

    std::copy_n(std::iota(begin), end-begin, std::back_inserter(sequence));
    

    Oder auch

    std::copy_n(std::iota(begin), end-begin, std::ostream_iterator<int>(std::cin, "\n"));
    

    oder auch

    std::for_each_n(std::iota(begin), end-begin, [](int i){
      // für alle i von begin bis end
    });
    

    Zur Namensgebung sage ich mal nichts, da sind die anderen Algorithmen auch nicht besser (von Streambufs ganz zu schweigen).



  • Dafür gibt's dann ja boost::iterator_facade oder wie es hieß!



  • Warum denn boost::, warum nicht std::?



  • Vor 10 Jahren wurde afaik noch VC6 benutzt. Das waren noch geile Zeiten!


Anmelden zum Antworten