2

I want to write a function like print_all described below.

#include <iterator>
#include <vector>

template <typename V>
void print_all(std::iterator<std::input_iterator_tag, V> it) {
  for (; it != std::end(it); ++it) {
    V item = *it;
    // do stuff with item
  }
}

int main() {
  std::vector<int> myvec (10);

  print_all(myvec.cbegin());

  return 0;
}

How do I declare print_all such that it can accept any iterator over type V?

Edit

I want to do this in a typesafe way. A better example of a use case would be an accumulator

#include <iterator>
#include <vector>
#include <functional>

template <typename V, typename K>
K accumulate(
      std::function<K(K, V)> accumulator,
      std::iterator<std::input_iterator_tag, V> it,
      std::iterator<std::input_iterator_tag, V> end,
      K initial) {
  K sum = initial;
  for (; it != end; ++it) {
    V item = *it;
    sum = accumulator(sum, item);
  }
  return sum;
}

Now you see why this question is not a duplicate of this. I feel like there would be a typesafe way to do this where the compiler makes sure the iterator iterates over the correct type. That is why I hesitate to accept Steve Lorimer's answer.

Community
  • 1
  • 1
charmoniumQ
  • 5,214
  • 5
  • 33
  • 51
  • 1
    `std::end(it)` will not work - iterators don't know about the container they're iterating over - you need to pass the end iterator in, found via `std::end(myvec)` or `myvec.end()` – Steve Lorimer Dec 15 '15 at 23:02
  • Or pass a reference to the container itself and use `std::begin()` and `std::end()` on it to get the iterators. – Kevin Dec 15 '15 at 23:05
  • Almost a duplicate, so here is a truck load of different ways to do it: http://stackoverflow.com/questions/10750057/c-printing-out-the-contents-of-a-vector – user4581301 Dec 15 '15 at 23:09
  • You should move your edit into a separate question. – Steve Lorimer Dec 15 '15 at 23:33
  • That's an interesting problem, @SteveLorimer . You far as I'm concerned, you answered the question as originally worded, and unfortunately Sam intended to ask a completely different question. – user4581301 Dec 15 '15 at 23:41
  • moved to here http://stackoverflow.com/q/34301584/1078199 – charmoniumQ Dec 15 '15 at 23:45
  • Question for @Sam: Why make the copy with `V item = *it;`? Something sneaky up your sleeve I'm not seeing? – user4581301 Dec 15 '15 at 23:45
  • Stop thinking `std::iterator` is something special. It's not. Also, you should pretty much never write `std::function*something containing deduced template parameters*/>`. – T.C. Dec 16 '15 at 00:26

1 Answers1

4

Assuming you have the required overloaded std::ostream operators, you can just make the actual iterator your function template's type

template<typename IterT>
void print_all(IterT begin, IterT end)
{
    while (begin != end)
        std::cout << *begin++ << ", ";
    std::cout << '\n';
}

As stated, this will only work if you have the requisite std::ostream& operator<<(...) overload.

You would call it as follows:

int main()
{
    std::vector<int> myvec;

    // populate myvec...

    print_all(std::begin(myvec), std::end(myvec));
    return 0;
}
Steve Lorimer
  • 27,059
  • 17
  • 118
  • 213
  • And if they want to ensure that it actually is an iterator, they can use this: http://stackoverflow.com/questions/12032771/how-to-check-if-an-arbitrary-type-is-an-iterator – KarenRei Dec 15 '15 at 23:09