-1

I need to create an iterator only for member element to iterate through container.

For example:

class A { int x; char y; };

std::vector<A> mycoll = {{10,'a'}, {20,'b'}, {30,'c'} };

Here mycoll.begin() will give me iterator of type A

But I require to write iterator to iterate over specific member ( say x A.x ) and let int_ite be the iterator for that integer.

Then I require

*(int_ite.begin() ) to return 10

*(++int_ite.begin() ) to return 20

and so on

also .end() would give end of iteration.

Is there any elegant way to create such an iterator? I require it to pass it to std::lower_bound()

addy
  • 103
  • 3
  • 12
  • You can't use `int_ite.begin()->x`? – NathanOliver Jan 11 '19 at 21:50
  • What exactly did you find to be a problem in creating the iterator? Have you tried to write the iterator yet? – eerorika Jan 11 '19 at 21:50
  • sure it is possible to implement something like an iterator only returning the field _x_, but so strange and complicated for nothing – bruno Jan 11 '19 at 21:54
  • @NathanOliver ```int_ite.begin()->x``` will give me the element directly. But I need to create iterator for that element to pass it to a function. – addy Jan 11 '19 at 21:54
  • @SergeyA its not – addy Jan 11 '19 at 21:56
  • @addy, just write a class, implement the usual iterator operations `*`, `++` etc. Formally you can look up the iterator requirements, implement all of those and you have an iterator. It's tedious but not difficult. – john Jan 11 '19 at 21:58
  • why do you need this? for example if you want to sort `mycoll` you would write a comparator that compares the member instead of having to create iterators that when dereferenced yield the member – 463035818_is_not_an_ai Jan 11 '19 at 21:59
  • @user463035818 For cases like std::sort it can be done without writing iterator I require it to pass it to std::lower_bound() – addy Jan 11 '19 at 22:04
  • better add that to the question, as it helps to answer – 463035818_is_not_an_ai Jan 11 '19 at 22:06
  • 1
    for `std::lower_bound` you don't need it either, a custom comparer do the job. – Jarod42 Jan 11 '19 at 22:08
  • 1
    Sidenote: Irf you ever find yourself in a position where you really do need to do this, [Mooing Duck has an excellent piece](https://stackoverflow.com/a/7759622/4581301) on how to get started making a container and its iterators. – user4581301 Jan 11 '19 at 22:12

2 Answers2

4

With range-v3, you may create view:

std::vector<A> mycoll = {{10,'a'}, {20,'b'}, {30,'c'} };

for (auto e : mycoll | ranges::view::transform(&A::x)) {
    std::cout << e << " "; // 10 20 30
}

And for lower_bound, range-v3 has projection:

auto it = ranges::v3::lower_bound(mycoll, value, std::less<>{}, &A::x);
// return iterator of mycoll directly :-)

Else with std, you my use custom comparer with std::lower_bound

auto it = std::lower_bound(mycoll.begin(), mycoll.end(),
                           value,
                           [](const A& a, int x){ return a.x < x; });
Jarod42
  • 203,559
  • 14
  • 181
  • 302
4

From cppreference (overload (2)):

template< class ForwardIt, class T, class Compare >
ForwardIt lower_bound( ForwardIt first, ForwardIt last, const T& value, Compare comp );

To find the lower bound with respect to the member x, you can pass a comparator that compares that member as the last parameter.

You typically pass a functor to algorithms that specifies how the container elements are processed or evaluated, instead of having to write complicated iterators. The support for writing your own fancy iterators is rather poor in the standard library, while the algorithms are rather powerful.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185