Как проверить, является ли параметр шаблона типом итератора или нет?

StackOverflow https://stackoverflow.com/questions/4335962

  •  30-09-2019
  •  | 
  •  

Вопрос

template<class T>
struct is_iterator
{
    static const bool value = ??? // What to write ???
};

int main()
{
    assert(false == is_iterator<int>::value);
    assert(true == is_iterator<vector<int>::iterator>::value);
    assert(true == is_iterator<list<int>::iterator>::value);
    assert(true == is_iterator<string::iterator>::value);
    assert(true == is_iterator<char*>::value); // a raw pointer is also an iterator
}

Вопрос в том: Как сделать пять заявлений о выдаче утверждений?

Это было полезно?

Решение

template<class T>
struct is_iterator
{   
    static T makeT();
    typedef void * twoptrs[2];  // sizeof(twoptrs) > sizeof(void *)
    static twoptrs & test(...); // Common case
    template<class R> static typename R::iterator_category * test(R); // Iterator
    template<class R> static void * test(R *); // Pointer

    static const bool value = sizeof(test(makeT())) == sizeof(void *); 
};

Другие советы

Приезжая сюда несколько лет спустя, где C ++ 11 и C ++ 14 облегчают такие вещи. Атмосфера итератор По своей сути, что -то, что является необоснованным, увеличивается. Если это Входной итератор, затем также сопоставимо. Пойдем с последним - так как это похоже на то, что вы хотите.

Самая простая версия - использовать void_t:

template <typename... >
using void_t = void;

Базовый вариант:

template <typename T, typename = void>
struct is_input_iterator : std::false_type { };

Действительный случай Специализации:

template <typename T>
struct is_input_iterator<T,
    void_t<decltype(++std::declval<T&>()),                       // incrementable,
           decltype(*std::declval<T&>()),                        // dereferencable,
           decltype(std::declval<T&>() == std::declval<T&>())>>  // comparable
    : std::true_type { };

Псевдоним:

template <typename T>
using is_input_iterator_t = typename is_input_iterator<T>::type;

Не нужно полагаться на iterator_category или использование утомительного стиля C ++ 03 проверки вещей с использованием разрешения перегрузки. Выражение Sfinae - это то, где он находится.


Как указывает г -н Уэйкли в комментариях, [iterator.traits] требует, чтобы:

требуется, чтобы если Iterator тип итератора, типы

iterator_traits<Iterator>::difference_type
iterator_traits<Iterator>::value_type
iterator_traits<Iterator>::iterator_category

быть определенным как тип разности итератора, тип значения и категория итератора соответственно.

Таким образом, мы можем определить нашу черту итератора, чтобы просто проверить это:

template <class T, class = void>
struct is_iterator : std::false_type { };

template <class T>
struct is_iterator<T, void_t<
    typename std::iterator_traits<T>::iterator_category
>> : std::true_type { };

Если iterator_traits<T>::iterator_category плохо образуется, тогда T не итератор.

Что ж, вы можете проверить, чтобы получить тип, чтобы иметь вложенный Typedef под названием iterator_category Это можно сделать с помощью SFINAE, и точную технику можно найти в Вики страница для SFINAE. Анкет Это не 100% метод, но все приличные итераторы должны предоставлять общие типы для итераторов, а iterator_category - это уникальная для итераторов. Также не забудьте проверить, является ли тип просто указатель. Указатели итераторы.

template < class T, class Enabler = void >
struct is_iterator : public boost::false_type { };

template < class T >
struct is_iterator< T, typename boost::enable_if_c<
        sizeof(*(*(T*)0)) + sizeof((*(T*)0)++) + sizeof(++(*(T*)0)) +
        sizeof((*(T*)0) == (*(T*)0)) + sizeof((*(T*)0) != (*(T*)0)) +
        sizeof((*(T*)0) = (*(T*)0)) >::type > : public boost::true_type { };

Первоначальный плакат пояснил, что они на самом деле просят способ идентифицировать входчик (см. http://en.cppreference.com/w/cpp/concept/inputiterator) Потому что они хотят иметь возможность увеличить и обозначить итератор. Это имеет очень простое решение Sfinae в стандартном C ++ 11, например, аналогично этому из GCC STL:

template<typename InputIterator>
using RequireInputIterator = typename
    std::enable_if<std::is_convertible<typename
                                       std::iterator_traits<InputIterator>::iterator_category,
                                       std::input_iterator_tag>::value>::type;

...

// Example: declare a vector constructor from a pair of input iterators.
template <typename InputIterator, typename = RequireInputIterator<InputIterator> >
    MyVector(InputIterator first, InputIterator last) { /* ... */ };

Это опирается на классы черт типа итератора, которые определяют типы, которые Армен Цируньян мысли, требовались от самих итераторов. (Итераторы могу Предоставьте эти Typedefs, но они также могут предоставить их в классах признаков, что необходимо для использования обнаженных указателей в качестве итераторов, и для этого необходимы стандартные реализации библиотеки.)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top