Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ how to create iterator over one field of a struct vector

I have a structure of all primitive types, like so:

struct record {
    int field1;
    double field2;
}

I have a vector of instances of this struct, like so:

vector<record> records;

Is it possible/what is the best way to create a vector<int>::iterator that will iterate over field1? What about if I used an array record records[n]? I need something that looks like vector<int>::iterator.

EDIT: I need something that IS a vector<int>::iterator.

like image 660
Brian Avatar asked Feb 12 '23 10:02

Brian


1 Answers

Making an iterator adaptor

First of all, the simplest solution is to iterate over the container and access the fields from the iterator.

for (auto&& r : records) {
    int value = r.field1;
    /* do something with 'value' */
}

Anyway, if you really want an iterator that returns field1 when dereferenced you can easily implement an iterator adaptor that derives from the container's own iterator.

struct my_it : public std::vector<record>::iterator {
    using std::vector<record>::iterator::iterator;
    int operator*() { return std::vector<record>::iterator::operator*().field1; }
};

And use it like this:

for (my_it it = std::begin(records); it != std::end(records); ++it) {
    int value = *it; // Dereferencing now returns 'field1'.
}

Is it an XY problem?

As explained in the answer by Ben Voigt, there is no way to create a std::vector<int>::iterator that iterates over something else than int elements stored in a contiguous array.

If you need a function that takes input iterators then make it a template function. This way it will work with iterators for any container type. This is how all the algorithms in the standard library is implemented.

template <typename InputIt>
void func(InputIt first, InputIt last) {
    for (; first != last; ++first) {
        value = *it; // Dereferences input iterator of any type.
    }
}

Iterators should be interfaced through their operations (i.e. read, increment, decrement, random access), not their explicit type. Iterators are categorized by the number of operations they support.

For instance, if you need to iterate over a range and read all the values in a single pass then you want input iterators as arguments. The type of the iterator itself should be irrelevant.

See this for more info about iterator categories

like image 133
Felix Glas Avatar answered Feb 15 '23 12:02

Felix Glas