In range-based for loop index bekommen



  • Wie bekomme ich aquivalent zu hier

    for(size_t i=0;i<size();++i){}
    

    diesen Index in zB

    for ( const auto& v : values ){}
    

    ?

    Habe zwar in die Dokumentation geschaut, bekomme es aber nicht hin und ich denke, einfach nachfragen geht schneller.



  • #include <iostream>
    
    int main()
    {
    	int values[]{ 1, 2, 3, 4, 5 };
    
    	for (const auto& v : values)
    	{
    		std::cout << &v - values << ": " << v << '\n';
    	}
    }
    


  • lemon03 schrieb:

    Habe zwar in die Dokumentation geschaut, bekomme es aber nicht hin und ich denke, einfach nachfragen geht schneller.

    Das hat mich auch schon öfter gewurmt, aber dafür ist das range-based for wohl zu generisch, um so etwas spezifisches wie einen Index zu unterstützen.
    Datenstrukturen, wie eine Verkette Liste z.B. haben keinen natürlichen "Index", lediglich Zeiger. Natürlich könnte das range-based for einen synthetischen
    Index zur Verfügung stellen, der die Position des Elements innerhalb der Range angibt, aber den mitzuführen wäre mit einem Overhead verbunden, welcher
    der C++Philosophie, für nichts zu zahlen, das man nicht benötigt widerspricht.

    Machs einfach manuell:

    std::size_t i = 0;
    for ( const auto& v : values ){ ++i; }
    


  • Swordfish schrieb:

    ...
    

    Das funktioniert zwar, aber man nagelt sich damit unnötig auf Datenstrukturen fest, bei der die Elemente direkt hintereinander im Speicher liegen.
    Den Index manuell mitzuzählen ist wahrscheinlich die elegantere Lösung 😉



  • Danke.

    Das Beispiel von Swordfish funktioniert auch nur mit ints und ähnlichen? Bei Objekten zB nicht mehr. Dafür ist das Mitzählen verblüffend simpel. Da habe ich gar nicht dran gedacht 😉



  • Gibt's da nichts von boost?

    #include <boost/range/adaptor/indexed.hpp>
    #include <boost/assign.hpp>
    #include <iterator>
    #include <iostream>
    #include <vector>
    
    int main(int argc, const char* argv[])
    {
        using namespace boost::assign;
        using namespace boost::adaptors;
    
        std::vector<int> input;
        input += 10,20,30,40,50,60,70,80,90;
    
        for (const auto& element : input | indexed(0))
        {
            std::cout << "Element = " << element.value()
                      << " Index = " << element.index()
                      << std::endl;
        }
    
        return 0;
    }
    


  • Bezüglich dem Overhead. Das Argument verstehe ich. Mir persönlich ist es nur wichtig, ob es schnell geht.

    Würde die boost-Lösung dabei Nachteile gegenüber dem reinen Mitzählen haben?



  • lemon03 schrieb:

    Das Beispiel von Swordfish funktioniert auch nur mit ints und ähnlichen? Bei Objekten zB nicht mehr.

    Finnegan schrieb:

    [...] man nagelt sich damit unnötig auf Datenstrukturen fest, bei der die Elemente direkt hintereinander im Speicher liegen.

    Was ist ein "Objekt"? Bei einem T[] , std::array<T> oder std::vector<T> tut es. Egal was T ist.



  • manni66 schrieb:

    input += 10,20,30,40,50,60,70,80,90;
        input | indexed(0)
    

    Man muss C++ einfach lieben für solche Möglichkeiten, die Sprache in gewissen grenzen de facto erweitern zu können - solange man es nicht übetreibt 😉
    Den += -Operator zum Hinzufügen von Elementen habe ich auch schon implementiert, aber der Komma-Operator ist hier noch ein echtes Sahnehäubchen 👍



  • Swordfish schrieb:

    Bei einem T[] , std::array<T> oder std::vector<T> tut es. Egal was T ist.

    Es ging mir nicht um das T sondern eben um die von dir genannten Datenstrukturen. Bei std::list<T> , database_result_set oder
    wasauchimmer wird es nicht mehr funktionieren. lemon03 hat uns leider nicht gesagt um was es sich bei values handelt, daher
    bevorzuge ich eine Lösung, die keine Annahmen über dessen Typ macht.



  • Das ich jetzt eigenen Code zeige, heißt nur, das ich im Moment zu faul, bin ein Beispiel zu schreiben.

    Hier funktioniert es nicht. Kann aber sein, das ich ein Verständnisfehler habe

    for ( const auto& charset : cycling_charset )
        {
            auto i = &charset - cycling_charset;
            paintModularPattern( paint, pattern, 0, 0, cycling_charset[ i ] );
            //paintModularPattern( paint, pattern, 0, 0, charset ); //ursprünglich
            console.writeBuffer();
            std::cout << i;
            key();
        }
    

    Mein Fehler kann auch sein, das values unklar ausgedrückt ist. Wollte eigentlich durch const auto& dies klarer machen, habe aber unsauber vorgearbeitet.



  • Welchen Typ hat denn cycling_charset ? Und was bedeutet "funktioniert nicht"?

    Ich würde die auskommentierte, "ursprünglich"-Zeile weiter verwenden. Wenn die schon nicht funktioniert,
    dann ist dein Problem nicht dadurch zu lösen, dass du via Index auf die Datenstruktur zugreifst.

    Überlege auch, ob du das i überhaupt benötigst. Wenn das std::cout << i nur eine Debug-Ausgabe sein soll,
    dann sehr wahrscheinlich nicht.



  • Finnegan schrieb:

    Swordfish schrieb:

    Bei einem T[] , std::array<T> oder std::vector<T> tut es. Egal was T ist.

    Es ging mir nicht um das T sondern eben um die von dir genannten Datenstrukturen.

    Das ist mir schon klar. Du hast es auch mit

    Finnegan schrieb:

    [...] man nagelt sich damit unnötig auf Datenstrukturen fest, bei der die Elemente direkt hintereinander im Speicher liegen.

    deutlich gesagt. Das quote Deiner Aussage war übrigens als Antwort auf

    lemon03 schrieb:

    Das Beispiel von Swordfish funktioniert auch nur mit ints und ähnlichen? Bei Objekten zB nicht mehr.

    gedacht.



  • cycling_charset ist ein vector aus charset .

    Aber nein, funktioniert alles. Ich wollte nur mal schnell "im laufenden Betrieb" nachschauen, an welcher Stelle ein bestimmter charset steht und die Stelle, das i , ausgeben lassen.

    Dabei bin ich, wie schon vorher ein paar Mal, auf diese Frage gestoßen. Und habe mich aufgerafft mal nachzufragen.Die obige Funktion mit ausgegebenen index existiert nur in diesem Moment und in diesem Forum.

    Wegen nicht funktioniert:

    error: no match for 'operator-' (operand types are 'const Charset*' and 'std::vector<Charset>')



  • lemon03 schrieb:

    Wegen nicht funktioniert:

    error: no match for 'operator-' (operand types are 'const Charset*' and 'std::vector<Charset>')

    #include <vector>
    #include <iostream>
    
    struct charset { charset(int foo) : foo{ foo } {}; int foo; };
    
    int main()
    {
    	std::vector<charset> cycling_charset{ 1, 2, 3 };
    
    	for (const auto& charset : cycling_charset)
    	{
    		auto i = &charset - &cycling_charset[0];
    		std::cout << i << '\n';
    	}
    }
    


  • wieder kein match , aber etwas ausgeführter

    auto i = &charset - cycling_charset[ 0 ];
    

    |error: no match for 'operator-' (operand types are 'const Charset*' and '__gnu_cxx::__alloc_traits<std::allocator<Charset> >::value_type {aka Charset}')|

    Aber liebe Leute 🙂 Wenn es kein höheren Grund, wie zB aus Erkenntnis-Gründen gibt, reicht mir das Mitzählen vollkommen aus. Ich brauchte diesen index genau einmal und hatte ihn.



  • lemon03 schrieb:

    wieder kein match , aber etwas ausgeführter

    auto i = &charset - cycling_charset[ 0 ];
    

    |error: no match for 'operator-' (operand types are 'const Charset*' and '__gnu_cxx::__alloc_traits<std::allocator<Charset> >::value_type {aka Charset}')|

    Mensch, Du hast den Adressoperator vor cycling_charset[0] übersehen.



  • Achhaje! 😃

    Na dann danke ich recht herzlich 🙂



  • Es sei angemerkt, dass man sich ein "range-based for mit Index" per Makro bauen kann, du kannst dann sowas schreiben:

    `foreach_i(v,values)std::cout << i << ": " << v << std::endl;

    foreach_i(v,values)v=i;`

    Bzw. FOREACH_I, um sich an Konventionen zu halten. Ein äquivalentes FOREACH_J bietet sich dann auch noch an.



  • ;sergey schrieb:

    Es sei angemerkt, dass man sich ein "range-based for mit Index" per Makro bauen kann, du kannst dann sowas schreiben:

    `foreach_i(v,values)std::cout << i << ": " << v << std::endl;

    foreach_i(v,values)v=i;`

    Klar geht das.

    Mir fällt jetzt aber z.B. nix ein wie man das mit range based for umsetzen könnte. Und wenn man range based for emulieren muss, dann kommt wieder so ein Monster wie BOOST_FOREACH raus.

    Hab ich da was übersehen, also geht das auch irgendwie einfach & elegant?



  • hustbaer schrieb:

    Hab ich da was übersehen, also geht das auch irgendwie einfach & elegant?

    Kommt drauf an, was man unter einfach und elegant versteht. Statt Macros zu verwenden würde ich std::for_each erweitern:

    #include <iostream>
    #include <vector>
    
    template<class InputIt, class Function>
    Function for_each(InputIt first, InputIt last, Function f)
    {
        for (int idx = 0; first != last; ++first, ++idx) {
            f(*first, idx);
        }
        return f;
    }
    
    int main()
    {
            std::vector<int> v = { 1, 2, 3, 4 };
    
            for_each( v.begin(), v.end(), []( auto& val, int idx ) {
                    std::cerr << idx << " = " << val << "\n";
            });
    
    }
    

Anmelden zum Antworten