0

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++?

Mark Ruzon
  • 3,297
  • 2
  • 15
  • 11
  • 2
    What's the overall problem at hand? By the way, your `value_type` struct is usually called `identity`. – GManNickG Feb 18 '10 at 20:14
  • I have images with different pixel types, some of which are structs and some of which are floats and some of which are ints. To do something mathematical with them (e.g. find the mean value) requires telling the compiler what type to use for the computation. And I already have VALUE_TYPE defined to return iterator_traits::value_type, so it's best to combine them into one construct. – Mark Ruzon Feb 19 '10 at 17:14

2 Answers2

3

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);
}
UncleBens
  • 40,819
  • 6
  • 57
  • 90
1

UncleBens has used SFINAE, but there is actually simpler:

template <class T>
struct value_type
{
  typedef typename T::value_type type;
};

Now, if you want to use it with a class you control, the easiest way is:

struct MyClass { typedef float value_type; };

BOOST_MPL_ASSERT((boost::is_same< MyClass::value_type,
                                  typename value_type<MyClass>::type >));

And if you want to use for a class you do not control, you still have specialization:

struct ThirdPartyClass {};

template <>
struct value_type<ThirdPartyClass> { typedef int type; }

If you try to use value_type for a class that does not have an inner typedef and for which no specialization is available, it's a compilation error (and a message you are not likely to understand at first glance...)

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • But since float::value_type does not exist, it will fail to compile for the key case of POD types. – Mark Ruzon Feb 19 '10 at 17:11
  • Like `std::iterator_traits` is specialized for pointers, you need to specialize your structure for each type that you cannot modify, yes. – Matthieu M. Feb 20 '10 at 12:49