I would like to create a construct similar to std::iterator_traits::value_type that can work seamlessly for all types using the same syntax. Imagine we have the following:
template <typename T>
struct value_type {
typedef T type;
};
#define VALUE_TYPE(T) typename value_type<T >::type
This will work for POD types. I can specialize it for my own class:
struct MyClass {
typedef float value_type;
};
template <>
struct value_type<MyClass> {
typedef MyClass::value_type type;
};
though I would prefer to avoid extra value_type instantiations in an ideal world.
The problem is with STL iterators. I need a specialization that gets me to the iterator hierarchy. This fails because the compiler chooses the base case:
template <>
struct value_type<std::_Iterator_base_aux> { // MSVC implementation
typedef value_type type;
};
Choosing a class higher up the hierarchy (_Iterator_with_base would be most natural because that is where value_type is defined) fails because it requires specifying all the iterator traits as template arguments.
Is what I'm trying to do even possible in C++?
You can use SFINAE to detect the presence of the value_type
typedef. No need to specialize for individual types (which might not be possible, since you'd be relying entirely on internal implementation details).
#include <vector>
template <class T>
struct has_value_type
{
typedef char true_type;
typedef char false_type[2];
//template not available if there's no nested value_type in U's scope
template <class U>
static true_type test(typename U::value_type* );
//fallback
template <class U>
static false_type& test(...);
//tests which overload of test is chosen for T
static const bool value = sizeof(test<T>(0)) == sizeof(true_type);
};
template <class T, bool b>
struct value_type_impl;
template <class T>
struct value_type_impl<T, false> //if T doesn't define value_type
{
typedef T type;
};
template <class T>
struct value_type_impl<T, true> //if T defines value_type
{
typedef typename T::value_type type;
};
template <class T>
struct value_type: value_type_impl<T, has_value_type<T>::value>
{
};
struct MyClass {
typedef float value_type;
};
template <class T>
int foo(T )
{
return typename value_type<T>::type();
}
int main()
{
foo(MyClass());
std::vector<int> vec;
foo(vec.begin());
foo(10);
}