japreiss
japreiss

Reputation: 11251

Deduce all but one template argument?

I'm trying to write a simple "Skip Iterator" with a template parameter for the number of elements to skip:

template <typename T, typename Iter, int Skip>
class SkipIterator
{
public:
    SkipIterator(Iter baseIter) :
        baseIter_(baseIter)
    {
    }

    void operator++()
    {
        baseIter_ += Skip;
    }

    T &operator*()
    {
        return *baseIter_;
    }

private:
    Iter baseIter_;
};

I'd like to be able to deduce the base Iter and T types like this:

std::vector<double> dataFromSomewhere;
SkipIterator<3> skipper(dataFromSomewhere.begin())

But the complier (VS2010) gives a "Too few template arguments" error.

Is there a way to do this?

Upvotes: 3

Views: 994

Answers (2)

Igor Tandetnik
Igor Tandetnik

Reputation: 52461

Template parameter deduction only happens in template function calls, never in variable declarations involving class template name. Also, if you want to deduce some but not all parameters, those you want deduced must be at the end.

All in all, you are looking for something like this:

template <int Skip, typename Iter>
auto make_skipper(Iter it)->SkptIterator<decltype(*it), Iter, Skip> {
  return SkptIterator<decltype(*it), Iter, Skip>(it);
}

auto skipper = make_skipper<3>(dataFromSomewhere.begin());

Upvotes: 6

Andy Prowl
Andy Prowl

Reputation: 126412

You can provide a helper function:

#include <iterator>

template <int Skip, typename Iter>
SkipIterator<typename std::iterator_traits<Iter>::value_type, Iter, Skip> 
    make_skip_iterator(Iter it)
{
    return SkipIterator<
        typename std::iterator_traits<Iter>::value_type, Iter, Skip
        >(it);
}

Which you would use this way:

std::vector<double> dataFromSomewhere;
auto skipper = make_skip_iterator<3>(dataFromSomewhere.begin());

Here is a live example.

Notice, that the C++14 version of the above helper function would look nicer (at least in the signature) thanks to return type deduction:

template <int Skip, typename Iter>
auto make_skip_iterator(Iter it)
{
    return SkipIterator<
        typename std::iterator_traits<Iter>::value_type, Iter, Skip
        >(it);
}

And the live example of course.

Upvotes: 8

Related Questions