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
.
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'.
}
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 (ie 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.
You're out of luck.
vector<int>::iterator
is not polymorphic 1 . There's no place to reach in and change the pointer step size. vector<int>::iterator
iterates a sequence of contiguous int
objects, only, and your int
objects are not stored contiguously.
This is why all the C++ standard algorithms are templated to accept iterators of any type. If you make your function a template accepting arbitrary iterator types, you can use an iterator adaptor like the one Snps wrote.
1 Polymorphism is slow relative to pointer arithmetic, no one would use std::vector
if it didn't have similar performance to a plain array
You can use lambdas on your original vector
.
For example:
for_each(records.begin(), records.end(), [](record& foo){/*operate on foo.field1 here*/});
Note that the vast majority of other algorithms also accept lambdas, so you can just iterate over your original vector
using the lambda to access just field1
.
I'm being presumptuous here but the behavior you are looking for seems to closely resemble that of a map
so you might wanna have a look at that.
I suppose that you're into Boost and evil you could also cobble something together with this: http://www.boost.org/doc/libs/1_57_0/libs/range/doc/html/range/reference/adaptors/reference/strided.html
It seems like you are asking for something like this
for(std::vector<record>::iterator i=records.begin(), end=records.end(); i!=end; ++i)
{
std::cout << i->field1 << std::endl;
}
Or in C++11
for(auto i=records.begin(), end=records.end(); i!=end; ++i)
{
std::cout << i->field1 << std::endl;
}
If you really want a member iterator, you can do something like this:
template <class M>
struct member_traits;
template <class T, class C>
struct member_traits<T C::*>
{
using class_type = C;
using return_type = T;
};
template <class Iterator, class C, class M>
struct member_iterator : Iterator
{
public:
using Iterator::Iterator;
template <class I, class Member>
member_iterator(I&& begin, Member&& member)
: std::vector<C>::iterator(std::forward<I>(begin))
, member(std::forward<Member>(member))
{
static_assert(std::is_member_pointer<Member>::value,
"Member must be dereferenceable");
}
typename member_traits<M>::return_type& operator*()
{
return (*static_cast<Iterator&>(*this)).*member;
}
private:
M member;
};
template <class Member, class Iterator>
auto make_member_iterator(Member&& member, Iterator&& it)
-> member_iterator<std::decay_t<Iterator>, typename member_traits<Member>::class_type, std::decay_t<Member>>
{
return {std::forward<Iterator>(it), std::forward<Member>(member)};
}
struct Record
{
int field1;
double field2;
};
int main()
{
std::vector<Record> v { {1, 1.0}, {2, 2.0}, {3, 3.0} };
for (auto it = make_member_iterator(&Record::field1, v.begin()); it != v.end(); ++it)
{
std::cout << *it << " ";
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.