Emiliano
Emiliano

Reputation: 31

Declare a template function which receives two generic iterator as parameters

I need to create a function which receives the iterator from the begin and the end of one container. Then it should show the content in the console.

My problem is that i dont know how to declare the iterator so that it can work with any type of container

This is what I did:

template <class T>
void print(typename iterator<T> &beg, typename iterator<T> &end) {
    while (beg != end) {
        cout << *beg << endl;
        beg++;
    }
}

Upvotes: 3

Views: 329

Answers (2)

Christian Hackl
Christian Hackl

Reputation: 27518

I need to create a function which receives the iterator from the begin and the end of one container.

Look how standard functions do it, for example std::find:

template< class InputIt, class T >
InputIt find( InputIt first, InputIt last, const T& value );

Observations:

  • InputIt does not need to inherit from the (now obsolete) std::iterator class or any other class. Among other advantages, this allows the function to be used with an array.
  • The same iterator type is used for start and end.
  • The iterators are passed by value.
  • The template parameter does not specify the iterators' value type.

Just do it exactly like that in your own code and you'll be fine:

#include <iostream>
#include <vector>

template <class Iterator> // not T
void print(Iterator beg, Iterator end) {
    while (beg != end) {
        std::cout << *beg << '\n';
        beg++;
    }
}

int main() {
    std::vector<int> const vec = { 1, 2, 3 };
    int const array[] = { 1, 2, 3 };
    using std::begin;
    using std::end;
    print(begin(vec), end(vec));
    print(begin(array), end(array));
}

Upvotes: 3

Silvio Mayolo
Silvio Mayolo

Reputation: 70257

The std::iterator class is really just a convenience; there's nothing in the standard that requires all iterators to inherit from it. Additionally, std::iterator doesn't have virtual methods, so it's not nearly the same thing as taking an Iterator<T> in, say, Java, where invoking the next() method would call the appropriate next(). You want to take a general type T, not just an std::iterator, so that the compiler will resolve to the correct overloads of operator++ and operator* at compile-time.

template <typename T>
void print(T iter, const T& end) {
    // Taking the first argument by value ensures that
    // we don't modify the caller's variables
    while (iter != end) {
        cout << *iter << endl;
        ++iter;
    }
}

This will work for any forward iterators, which is what you're dealing with 99% of the time.

Upvotes: 5

Related Questions