dguan
dguan

Reputation: 1033

Is there a way to let template function automatically deduce an iterator's underlying data type?

I have a function where I need an iterator's underlying data type as return type, like this:

#include <iostream>
#include <vector>
#include <iterator>

template<class T, class ForwardIterator>
std::vector<T> get_odd(ForwardIterator data_begin, ForwardIterator data_end)
{
    std::vector<T> ret;
    std::copy_if(data_begin, data_end, std::back_inserter(ret), [](int x) { return x % 2; });
    return ret;
}

int main()
{
    std::vector<int> vi { 1, 2, 3, 4, 5 };
    for (auto i : get_odd<int>(vi.begin(), vi.end()))
        std::cout << i << ", ";
    std::cout << std::endl;

    std::vector<unsigned int> vui{ 9UL, 8UL, 7UL, 6UL, 5UL };
    // Note the 'char' I provided to the function, this will print weird chars
    for (auto i : get_odd<char>(vui.begin(), vui.end()))
        std::cout << i << ", ";
    std::cout << std::endl;

    return 0;
}

In the main(), I have to explicitly provide data type 'int' or 'char' to the get_odd function, is there a way to find out iterator's underlying data type, and let template automatically deduct the correct data type?

Upvotes: 5

Views: 305

Answers (4)

Casey
Casey

Reputation: 42594

This comes up often enough that I use a convenient template alias to wrap iterator_traits:

template <typename I>
using ValueType = typename std::iterator_traits<I>::value_type;

template<class ForwardIterator>
std::vector<ValueType<ForwardIterator>>
get_odd(ForwardIterator data_begin, ForwardIterator data_end)
{
    std::vector<ValueType<ForwardIterator>> ret;
    std::copy_if(data_begin, data_end, std::back_inserter(ret), [](int x) {
        return x % 2;
    });
    return ret;
}

Upvotes: 2

dlf
dlf

Reputation: 9403

If your compiler supports C++11, you can use:

#include <type_traits>
// ...
typename std::remove_reference<decltype(*data_begin)>::type

And probably typedef for convenience:

typedef typename std::remove_reference<decltype(*data_begin)>::type ContainedType;
std::vector<ContainedType> ret;

Upvotes: 2

Piotr Skotnicki
Piotr Skotnicki

Reputation: 48527

Use std::iterator_traits:

template<class ForwardIterator>
std::vector<typename std::iterator_traits<ForwardIterator>::value_type> get_odd(ForwardIterator data_begin, ForwardIterator data_end)
{
    ....
}

Upvotes: 0

Iterator properties can be queried using std::iterator_traits:

template<class ForwardIterator>
std::vector<typename std::iterator_traits<ForwardIterator>::value_type> 
get_odd(ForwardIterator data_begin, ForwardIterator data_end)
{
    std::vector<typename std::iterator_traits<ForwardIterator>::value_type> ret;
    std::copy_if(data_begin, data_end, std::back_inserter(ret), [](int x) { return x % 2; });
    return ret;
}

Upvotes: 6

Related Questions