Может ли C ++ value_type быть расширен от iterator_traits до всех типов? - PullRequest
0 голосов
/ 18 февраля 2010

Я хотел бы создать конструкцию, аналогичную std :: iterator_traits :: value_type, которая может беспрепятственно работать для всех типов, используя один и тот же синтаксис. Представьте, что у нас есть следующее:

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

#define VALUE_TYPE(T) typename value_type<T >::type

Это будет работать для типов POD. Я могу специализировать его для своего класса:

struct MyClass {
  typedef float value_type;
};

template <>
struct value_type<MyClass> {
  typedef MyClass::value_type type;
};

хотя я бы предпочел избежать дополнительных экземпляров value_type в идеальном мире.

Проблема с итераторами STL. Мне нужна специализация, которая приводит меня к иерархии итераторов. Это терпит неудачу, потому что компилятор выбирает базовый вариант:

template <>
struct value_type<std::_Iterator_base_aux> {  // MSVC implementation
  typedef value_type type;
};

Выбор класса выше по иерархии (_Iterator_with_base был бы наиболее естественным, потому что именно там определен value_type) терпит неудачу, потому что требует указания всех черт итератора в качестве аргументов шаблона.

Возможно ли то, что я пытаюсь сделать, даже в C ++?

Ответы [ 2 ]

3 голосов
/ 18 февраля 2010

Вы можете использовать SFINAE для обнаружения присутствия определения типа value_type. Нет необходимости специализироваться на отдельных типах (что может быть невозможно, поскольку вы полностью полагаетесь на внутренние детали реализации).

#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);
}
1 голос
/ 19 февраля 2010

UncleBens использовал SFINAE, но на самом деле все проще:

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

Теперь, если вы хотите использовать его с классом, которым вы управляете, самый простой способ:

struct MyClass { typedef float value_type; };

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

И если вы хотите использовать класс, который вы не контролируете, у вас все еще есть специализация:

struct ThirdPartyClass {};

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

Если вы попытаетесь использовать value_type для класса, который не имеет внутреннего typedef и для которого недоступна специализация, это ошибка компиляции (и сообщение, которое вы вряд ли поймете на первый взгляд). .)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...