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

后端 未结 9 1250
终归单人心
终归单人心 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:32

    This question is tagged c++14, but I would like to post an answer for c++20 because there's a really beautiful solution that I posted here

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

    I wrote something for this a while back.

    Essentially, you need to wrap an iterator and give it pair semantics.

    AFAIK, there's nothing like this built into the language. And I don't think boost has it either. You pretty much have to roll your own.

    // Wraps a forward-iterator to produce {value, index} pairs, similar to
    // python's enumerate()
    template <typename Iterator>
    struct EnumerateIterator {
    private:
      Iterator current;
      Iterator last;
      size_t index;
      bool atEnd;
    
    public:
      typedef decltype(*std::declval<Iterator>()) IteratorValue;
      typedef pair<IteratorValue const&, size_t> value_type;
    
      EnumerateIterator()
        : index(0), atEnd(true) {}
    
      EnumerateIterator(Iterator begin, Iterator end)
        : current(begin), last(end), index(0) {
        atEnd = current == last;
      }
    
      EnumerateIterator begin() const {
        return *this;
      }
    
      EnumerateIterator end() const {
        return EnumerateIterator();
      }
    
      EnumerateIterator operator++() {
        if (!atEnd) {
          ++current;
          ++index;
    
          atEnd = current == last;
        }
    
        return *this;
      }
    
      value_type operator*() const {
        return {*current, index};
      }
    
      bool operator==(EnumerateIterator const& rhs) const {
        return
          (atEnd && rhs.atEnd) ||
          (!atEnd && !rhs.atEnd && current == rhs.current && last == rhs.last);
      }
    
      bool operator!=(EnumerateIterator const& rhs) const {
        return !(*this == rhs);
      }
    
      explicit operator bool() const {
        return !atEnd;
      }
    };
    
    template<typename Iterable>
    EnumerateIterator<decltype(std::declval<Iterable>().begin())> enumerateIterator(Iterable& list) {
      return EnumerateIterator<decltype(std::declval<Iterable>().begin())>(list.begin(), list.end());
    }
    
    template<typename ResultContainer, typename Iterable>
    ResultContainer enumerateConstruct(Iterable&& list) {
      ResultContainer res;
      for (auto el : enumerateIterator(list))
        res.push_back(move(el));
    
      return res;
    }
    
    0 讨论(0)
  • 2020-12-21 01:33

    Boost::Range supports this as of 1.56.

    #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 : index(input, 0)) // function version
        for (const auto& element : input | indexed(0))      
        {
            std::cout << "Element = " << element.value()
                      << " Index = " << element.index()
                      << std::endl;
        }
    
        return 0;
    }
    
    0 讨论(0)
提交回复
热议问题