range based for-loop : wie kommt man an den Index?



  • Es wurde richtig bemerkt, dass man mit static vorsichtig sein soll, weil das Programmstück nur beim ersten und einzigen Durchlauf funktioniert. Der Grund ist ja der, dass solche Variablen nicht auf dem Stack angelegt werden, sondern zu Start des Programms irgendwo im Freispeicher und dabei auch inititalisiert werden und somit bei Wiedereintritt in den Block keine weitere Initialisierung auftritt.

    Wenn garantiert ist, dass der Block nur ein einziges Mal ausgeführt wird, ist das ok, z.B. wenn der Block kein Funktionskörper ist, sondern einfach so im Hauptprogramm steht, wie das bei einer Initialisierung sein kann.

    Verwendet man z. B. ein Funktionsobjekt, dass den Index mitzählen und die Berechnungen durchführen soll, so tritt genau dieser Effekt auch ein, dass nämlich bei der Konstruktion des Objektes ein einziges Mal inititalisiert wird und sonst nie wieder. Man muss also auch hier ggf. die Lebensdauer des Objektes begrenzen, damit bei Wiederholung kein Unsinn passiert.

    {
    for(auto & x : X)
       {
       static unsigned i = 0;
       x = somefunc(i++);
       }
    }
    

    ist also ähnlich wie:

    class funcobj
       { 
       public: 
       funcobj():i(0){};
       float operator()(){return somefunc(i++);};
       private:
       unsiged i;
       };
    
    ...
    
    funcobj gen;
    generate(X.begin(),X.end(),gen);
    generate(X.begin(),X.end(),gen);  //??
    

    Es ist ganz interessant, dass in Büchern steht, man nehme halt ein Funktionsobjekt, aber über die Wiederholung steht da nichts.



  • Die Laufzeiten sind auch ganz interessant.
    Es scheint so, als haben die Lösungen mit range-based-for und generate die Nase weit vorne, mit ca. nur 30% der Zeit, die die klassische for-Schleife mit oder ohne Iteratoren braucht. Natürlich ist das bei size() = 100 uninteressant. Aber ich nehme ja C++, weil die Problemgröße interessant ist, also eher size() > 1e8.



  • wastl schrieb:

    Es ist ganz interessant, dass in Büchern steht, man nehme halt ein Funktionsobjekt, aber über die Wiederholung steht da nichts.

    Dann erzeugt man eben ein neues.



  • kkaw schrieb:

    Beispiel für das Mitzählen

    vector<double> x;
    for (auto t : counted(x)) {
       // t könnte hier ein tuple<decltype(x.size()),double&> sein
       cout << "Der " << (1+get<0>(t)) << ". Eintrag ist "
            << get<1>(t) << endl;
    }
    

    Das ist aber etwas unschön mit dem Tupel. Lieber ein Typ mit verständlich benannten Elementen:

    vector<double> x;
    for (auto t : counted(x)) {
       // t könnte hier ein tuple<decltype(x.size()),double&> sein
       cout << "Der " << (1+t.index) << ". Eintrag ist "
            << t.value << endl;
    }
    


  • ➡

    vector<double> x{1.1,2.2,3.3,4.4,5.5,6.6};
    auto indexed = x | boost::adaptors::indexed(1);
    for (auto t : boost::irange(begin(indexed), end(indexed)))
        cout << "Der " << t.index() << ". Eintrag ist "
             << *t << endl;
    


  • TyRoXx schrieb:

    wastl schrieb:

    Es ist ganz interessant, dass in Büchern steht, man nehme halt ein Funktionsobjekt, aber über die Wiederholung steht da nichts.

    Dann erzeugt man eben ein neues.

    Genau. Ich habe es nur erwähnt, weil sich Leute über ein Beispiel furchtbar aufgeregt haben, dass man ebenso betitteln könnte: einmal ausführren, wenn zweimal, dann Block erneut hinschreiben (man braucht eine Inititalisierung nur einmal, aber egal...)



  • Ich benutze dafür ein Makro:

    foreach_i(x,X)x*=i;
    

    Quadratisch, praktisch, gut.

    Passend gibt es auch ein foreach_j für den Fall der Fälle.



  • arens schrieb:

    Ich benutze dafür ein Makro:

    foreach_i(x,X)x*=i;
    

    Quadratisch, praktisch, gut.

    Passend gibt es auch ein foreach_j für den Fall der Fälle.

    So viel kürzer als

    for (auto it : with_index(x))
        *it *= it.index;
    

    ist das auch nicht.



  • boost based for loop schrieb:

    ➡

    vector<double> x{1.1,2.2,3.3,4.4,5.5,6.6};
    auto indexed = x | boost::adaptors::indexed(1);
    for (auto t : boost::irange(begin(indexed), end(indexed)))
        cout << "Der " << t.index() << ". Eintrag ist "
             << *t << endl;
    

    Sehr nett! Wusste gar nicht, dass man irange auch so verwenden kann. Dachte, ich bekomme damit nur Ganzzahl-Sequenzen hin. Aber das hier ist ja eine Sequenz von Iteratoren. Scheint laut Doku nicht vorgesehen und eher ein "Unfall" zu sein.


Anmelden zum Antworten