JT1
JT1

Reputation: 453

C++ generic iterator

I'm not sure if the answers I was able to find are the easiest way to do what I need. The simple template that I would know how to modify into a full solution to my problem would be code that accomplishes the following:

  1. Takes as input two iterators pointing to the beginning and end of an iterable container (vector, list...) containing things of value type T.

  2. Returns a std::vector<T> containing an element-by-element copy of the input container in whatever order accomplished by iterating the input container from beginning to end.

Something non-functioning would be like follows:

 template<typename Iterator, typename T>
 std::vector<T> dumb_copy(Iterator first, Iterator last) { ... }

Problem is that I would need the compiler to somehow check that I'm given iterators pointing to something of type T.

I'm currently learning C++ and writing as practice the most generic implementations of certain algorithms that I can think of, so I want to get the best practices right from the start. If there's an easy way of doing this using C++11 constructs, that's fine with me.

Upvotes: 2

Views: 2179

Answers (3)

Dietmar K&#252;hl
Dietmar K&#252;hl

Reputation: 153792

You can just create a std::vector<T> with a type matching the result of *it for one of the iterators:

#include <type_traits>
#include <vector>
template <typename Iterator>
auto dump_copy(Iterator begin, Iterator end)
    -> std::vector<typename std::decay<decltype(*begin)>::type> {
    return std::vector<typename std::decay<decltype(*begin)>::type(begin, end);
}

With C++14 you can replace typename std::decay<X>::type by std::decay_t<X>.

Upvotes: 2

Galik
Galik

Reputation: 48605

You don't need to do this because the standard library containers already work this way. So you can create a std::vector from two iterators directly:

#include <string>
#include <vector>
#include <iostream>

int main()
{
    std::string s = "hello"; // iterable container

    // construct a vector using two iterators
    std::vector<std::string::value_type> v(s.begin(), s.end());

    // check the results
    for(unsigned i = 0; i < v.size(); ++i)
        std::cout << v[i];
    std::cout << '\n';
}

Upvotes: 2

cdhowie
cdhowie

Reputation: 168958

You can simply use traits to remove the T type completely, allowing it to be determined automatically:

template <typename Iterator>
std::vector<typename std::iterator_traits<Iterator>::value_type>
    dumb_copy(Iterator first, Iterator last)
{
    std::vector<typename std::iterator_traits<Iterator>::value_type> copy;

    // Populate the copy vector

    return copy;
}

In particular, note that std::iterator_traits has a specialization when the iterator type is a pointer, so this will allow your function to "just work" even when it is passed pointers instead of "true" iterator objects.

Upvotes: 9

Related Questions