3

I have some code that enumerates some data, something like this:

int count;
InitDataEnumeration(/* some init params */, &count);

for (int i = 0; i < count; i++) 
{ 
    EnumGetData(i, &data);
    // process data ...
}

I'd like to convert this code in a form suitable to C++11's range-for.

I was thinking of defining a DataEnumerator wrapper class, whose constructor would call the above InitDataEnumeration() function.

The idea would be to use this wrapper class like this:

DataEnumerator enumerator{/* init params*/};

for (const auto& data : enumerator) 
{
    // process data ...
}

How could the former int-indexed for loop be refactored in the latter range-based form?

I was thinking of exposing begin() and end() methods from the enumerator wrapper class, but I don't know what kind of iterators they should return, and how to define such iterators.

Note that the iteration process is forward-only.

Mr.C64
  • 41,637
  • 14
  • 86
  • 162
  • I don't see what kind of answer to my question is given in the "duplicate" linked question. – Mr.C64 Sep 14 '16 at 20:34

4 Answers4

2

What you are looking for can be done with boost::irange. It will construct a lazy range of integers in the range [first, last) and you can just drop it right in like you use i in your for loop.

for (int i = 0; i < count; i++) 
{ 
    EnumGetData(i, &data);
    // process data ...
}

Becomes

for (auto i : boost::irange(0, count))
{
    EnumGetData(i, &data);
    // process data ...
}
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • Sorry, but this doesn't add anything good to the index for. Please see my second code snippet for what was the desired code. – Mr.C64 Sep 14 '16 at 20:03
1

You require an input iterator this example completely copied from http://en.cppreference.com/w/cpp/iterator/iterator :

#include <iostream>
#include <algorithm>

template<long FROM, long TO>
class Range {
public:
    // member typedefs provided through inheriting from std::iterator
    class iterator: public std::iterator<
                    std::input_iterator_tag,   // iterator_category
                    long,                      // value_type
                    long,                      // difference_type
                    const long*,               // pointer
                    long                       // reference
                                  >{
    long num = FROM;
    public:
    explicit iterator(long _num = 0) : num(_num) {}
    iterator& operator++() {num = TO >= FROM ? num + 1: num - 1; return *this;}
    iterator operator++(int) {iterator retval = *this; ++(*this); return retval;}
    bool operator==(iterator other) const {return num == other.num;}
    bool operator!=(iterator other) const {return !(*this == other);}
    reference operator*() const {return num;}
    };
    iterator begin() {return iterator(FROM);}
    iterator end() {return iterator(TO >= FROM? TO+1 : TO-1);}
};

int main() {
    // std::find requires a input iterator
    auto range = Range<15, 25>();
    auto itr = std::find(range.begin(), range.end(), 18);
    std::cout << *itr << '\n'; // 18

    // Range::iterator also satisfies range-based for requirements
    for(long l : Range<3, 5>()) {
    std::cout << l << ' '; // 3 4 5
    }
    std::cout << '\n';
}
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
rahnema1
  • 15,264
  • 3
  • 15
  • 27
  • 1
    I rolled the edit back to have quotes as this is copied material and should be marked up as such – NathanOliver Sep 14 '16 at 19:41
  • 2
    Also note that this is a template so it only works when the size is know at compile time. If it is run time dependent this will not work. – NathanOliver Sep 14 '16 at 19:44
0

You are right about begin() and end(), whatever they return should supply:

  • operator++ (prefix only is enough)
  • operator!=
  • operator*

All pretty self-explanatory.

Notice that no traits or categories are required, as would be for iterators intended for some standard library algorithms - just bare minimum.

Ap31
  • 3,244
  • 1
  • 18
  • 25
-1

for(auto x : y) Here, y must be an object of a class that has a begin() method and an end() method that each returns an object implementing the concept of an iterator. The iterator must be incrementable (iter++), must be able to accurately determine if it is equal to another iterator of the same kind (via !=) and must de-reference to whatever x needs to be.

This is something you should consider doing if you either A) are bored or otherwise have nothing better to do or B) have a legit need to. While this is not difficult to do, neither is it trivial.

Altainia
  • 1,347
  • 1
  • 7
  • 11