Reputation: 352
I have a type
typedef std::pair<ConstIterator, ConstIterator> Range;
with
typedef typename std::vector<T>::const_iterator ConstIterator;
I would now like to use std::iterator_traits to deduce the type the iterators of a Range are pointing to.
Could anybody please tell me how I can achieve this, from an object of type Range?
Upvotes: 1
Views: 473
Reputation: 63154
You're explicitly allowed to add template specializations to the std
namespace for user-defined types (thanks Barry for the precision !). If you rework your Range
to be an actual type (not just a typedef), you can do this :
struct Range : std::pair<ConstIterator, ConstIterator> {
using std::pair<ConstIterator, ConstIterator>::pair;
};
namespace std {
template <>
struct iterator_traits<Range> : iterator_traits<ConstIterator> {};
}
When you buff your Range
a bit, I expect this to evolve into :
namespace std {
template <class T>
struct iterator_traits<Range<T>> : iterator_traits<T> {};
}
Upvotes: 0
Reputation: 275896
This will support both your pair
based ranges, and most iterables:
template<class R>
struct value_type {
using iterator_type = decltype( std::begin(std::declval<R>()) );
using type=typename std::iterator_traits<iterator_type>::value_type;
};
template<class It>
struct value_type<std::pair<It,It>> {
using type=typename std::iterator_traits<It>::value_type;
};
template<class X>
using value_t = typename value_type<X>::type;
note that the value type of a const iterator is a non-const value.
The above is not SFINAE friendly -- an industrial quality one would be.
Upvotes: 0
Reputation: 303890
You can write a type trait, partially specialized on a pair
:
template <typename T>
struct value_type {
using type = typename std::iterator_traits<T>::value_type;
};
template <typename T>
struct value_type<std::pair<T, T>>
: value_type<T>
{ };
Upvotes: 1