Reputation: 41
How do you create an iterator that restricts the underlying type? For example, I want to create functions like the following:
void functionThatOperatesOnPointSequence(PointIterator begin, PointIterator end);
Where the sequence of Point
objects may be stored in different ways. My use case would have the additional complexity that Point
would be a templated type. i.e. Point<int>
or Point<double>
would be equally valid.
Solutions using C++11/14 or Boost are valid and preferable.
Upvotes: 4
Views: 878
Reputation: 275310
Here is a bit of template metaprogramming. is_template_instance
takes a template that takes only types, and a type, and returns true if that second type is an instance of the first template.
template<template<class...>class Z, class T>
struct is_template_instance:std::false_type{};
template<template<class...>class Z, class...Ts>
struct is_template_instance<Z,Z<Ts...>>:std::true_type{};
Now, we want to query the value type of the iterator. We can use std::iterator_traits
directly, or use an alias like this:
template<class It>
using it_value_type = typename std::iterator_traits<It>::value_type;
We compose the two above to write a is_point_iterator
template:
template<class It>
using is_point_iterator = is_template_instance< Point, it_value_type<It> >;
Note that if you pass this non-iterators, it may not fail in a friendly manner, or it may return the wrong result (std::iterator_traits
does not guarantee sensible return values for non-iterators).
But that tends to be caught in template bodies.
template<class PointIterator,
class=std::enable_if_t< is_point_iterator<PointIterator>::value >
>
void functionThatOperatesOnPointSequence(PointIterator begin, PointIterator end) {
// ...
}
there is only limited usefulness.
You could extract the value type from the PointIterator in a more SFINAE friendly manner, for example:
template<class It>
using it_value_type = std::decay_t<decltype(*std::declval<It>())>;
if you need SFINAE support.
Upvotes: 2