Is there an equivalent to the range-based `enumerate` loop from python in modern C++?

后端 未结 9 1249
终归单人心
终归单人心 2020-12-21 00:48

Is there an equivalent to the range-based enumerate loop from python in C++? I would imagine something like this.

enumerateLoop (auto counter, a         


        
相关标签:
9条回答
  • 2020-12-21 01:14

    You can also more elegantly use the auto ranges available since C++11:

    int i = 0;
    for (auto& el : container){
        charges.at(counter) = el[0];
        aa.at(counter) = el[1];
        ++i;
    }
    

    You still have to count the i up by hand, though.

    0 讨论(0)
  • 2020-12-21 01:17

    Tobias Widlund wrote a nice MIT licensed Python style header only enumerate (C++17 though):

    GitHub

    Blog Post

    Really nice to use:

    std::vector<int> my_vector {1,3,3,7};
    
    for(auto [i, my_element] : en::enumerate(my_vector))
    {
        // do stuff
    }
    
    0 讨论(0)
  • 2020-12-21 01:18

    C++17 and structured bindings makes this look OK - certainly better than some ugly mutable lambda with a local [i = 0](Element&) mutable or whatever I've done before admitting that probably not everything should be shoehorned into for_each() et al. - and than other solutions that require a counter with scope outside the for loop.

    for (auto [it, end, i] = std::tuple{container.cbegin(), container.cend(), 0};
         it != end; ++it, ++i)
    {
          // something that needs both `it` and `i`ndex
    }
    

    You could make this generic, if you use this pattern often enough:

    template <typename Container>
    auto
    its_and_idx(Container&& container)
    {
        using std::begin, std::end;
        return std::tuple{begin(container), end(container), 0};
    }
    
    // ...
    
    for (auto [it, end, i] = its_and_idx(foo); it != end; ++it, ++i)
    {
        // something
    }
    

    C++ Standard proposal P2164 proposes to add views::enumerate, which would provide a view of a range giving both reference-to-element and index-of-element to a user iterating it.

    We propose a view enumerate whose value type is a struct with 2 members index and value representing respectively the position and value of the elements in the adapted range.

    [ . . .]

    This feature exists in some form in Python, Rust, Go (backed into the language), and in many C++ libraries: ranges-v3, folly, boost::ranges (indexed).

    The existence of this feature or lack thereof is the subject of recurring stackoverflow questions.

    Hey, look! We're famous.

    0 讨论(0)
  • 2020-12-21 01:27

    There is a pre C++11 solution in boost to this: boost.range.indexed. Unfortunately it doesn't work with C++11 range based for-loops, only old style verbose loops. However with C++17 it should be become (almost) as easy as in python using structured bindings

    Then it should be possible implement something that works like this:

    for (auto& [n,x] : enumerate(vec)) x = n;
    

    So, a bit of waiting still ;)

    0 讨论(0)
  • 2020-12-21 01:31

    Enumeration of multiple variables has been an idiom since C. The only complication is that you can't declare both variables in the initializer of the for loop.

    int index;
    for (auto p = container.begin(), index = 0; p != container.end(); ++p, ++index)
    

    I don't think it gets any simpler (or more powerful) than that.

    0 讨论(0)
  • 2020-12-21 01:31

    Here's a macro-based solution that probably beats most others on simplicity, compile time, and code generation quality:

    #include <iostream>
    
    #define fori(i, ...) if(size_t i = -1) for(__VA_ARGS__) if(i++, true)
    
    int main() {
        fori(i, auto const & x : {"hello", "world", "!"}) {
            std::cout << i << " " << x << std::endl;
        }
    }
    

    Result:

    $ g++ -o enumerate enumerate.cpp -std=c++11 && ./enumerate 
    0 hello
    1 world
    2 !
    
    0 讨论(0)
提交回复
热议问题