2

I know there is no abstract base class for iterators in C++ but I have a specific question I can't find an answer to. In the documentation for list::begin() this example of iterating over list is given:

std::cout << "mylist contains:";
for (std::list<int>::iterator it=mylist.begin(); it != mylist.end(); ++it)
  std::cout << ' ' << *it;
...

And for list::rbegin() this is given:

std::cout << "mylist backwards:";
for (std::list<int>::reverse_iterator rit=mylist.rbegin(); rit!=mylist.rend(); ++rit)
  std::cout << ' ' << *rit;
...

Do I really have to specify that the iterator is a list iterator - std::list<int>::iterator? This means I can't generalize between iterators over the same type (say int) from different containers?! And further, do I really have to distinguish between a std::list::iterator and std::list::reverse_iterator? According to the documentation they are both ForwardIterators?

How can I avoid these qualifications? It seems against the whole point of having iterators.

8
  • Use templates.. that's the whole point of having templates :) Commented Jun 10, 2014 at 3:40
  • @MattMcNabb What? I am using templates. Commented Jun 10, 2014 at 3:45
  • Deduce the iterator type from the template parameters, or use a similar model with ForwardIterator etc. that the standard library does. I can provide an example if you show some more code Commented Jun 10, 2014 at 4:11
  • @MattMcNabb Hmm OK so template the iterator type. Are you suggesting I do something like this: template <class T, class U> void iterate_it(T<U>::iterator it);. I can't get that to compile. Commented Jun 10, 2014 at 6:42
  • You'd need to show the function this is in (i.e. where mylist comes from) Commented Jun 10, 2014 at 6:58

2 Answers 2

3

You tagged C++11, so to avoid those declarations, you can use a range for-loop to iterate between begin() and end():

std::cout << "mylist contains:";
for (auto item : mylist)
  std::cout << item << *it;

And yes, you would need to differentiate the case for reverse iterators, since they really are another type of iterators (going reverse on the std::list, which is a doubly linked list, so the output of your loop will indeed be different).

EDIT:

The STL way of avoiding writing handcrafted loops for different containers or iterators types, is to use generic algorithms taking a pair of iterators as their arguments:

std::for_each (mylist.begin(), mylist.end(), myfunction);

So you can reuse your algorithms with any kind of containers or iterators, without rewriting code. Such algorithms are templates, templated with the iterator types, allowing to provide specialization in some cases (e.g. its easier to do std::sort with random iterators than with forward iterators).

Sign up to request clarification or add additional context in comments.

7 Comments

quantdev; reverse has different implementation obviously but the interface is the same. Also the "auto" is compile time. What about say, providing the iterator from say vector.begin(), and list.begin() to a function in a generic way?
@FrancisM.Bacon: Make the function a template.
@FrancisM.Bacon Your function should take an iterator type as a template argument then. Take a look at any of the algorithms in the standard library
Use templates for that, all the information is available at compile time (this is what auto does under the covers, too)
@FrancisMBacon : see my edit about template algorithms and the STL, hope this helps.
|
1

Use auto, then you don't have to mention the type of container

for (auto it=mylist.begin(); it != mylist.end(); ++it)
  std::cout << ' ' << *it;

and

for (auto rit=mylist.rbegin(); rit!=mylist.rend(); ++rit)
  std::cout << ' ' << *rit;

Or use decltype

for (decltype(mylist)::iterator it=mylist.begin(); it != mylist.end(); ++it)
  std::cout << ' ' << *it;

and

for (decltype(mylist)::reverse_iterator rit=mylist.rbegin(); rit!=mylist.rend(); ++rit)
  std::cout << ' ' << *rit;

Or use a range-based for

for(auto const& elem : mylist) 
  std::cout << ' ' << elem;

And if you use Boost you can extend this functionality to the reverse iterator too

for(auto const& elem : (mylist | boost::adaptors::reversed)) {
  std::cout << ' ' << elem;

6 Comments

I left you the decltype you could have left me the range loop ;) - nice answer now +1.
@quantdev Ha! I was still editing when you posted, didn't see your answer till I was done :P
For the classic for loop, why wouldn't you just use auto in that case also? Is there some advantage in using decltype there? Or do you just prefer it?
@BenjaminLindley No, just didn't think of it :)
Ok I see I can use for(:) or for_each(), but I don't know how to do what they are doing. Looking at the docs for std::sort() for example it says the protocol is void sort (RandomAccessIterator first, RandomAccessIterator last); but as far as I can tell RandomAccessIterator is not a class!?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.