11
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
}

问题是:如何使五个断言语句通过?

4

5 回答 5

15

几年后来到这里,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 就是它所在的位置。


正如 Wakely 先生在评论中指出的那样,[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不是迭代器。

于 2015-07-14T14:28:14.403 回答
6
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 *); 
};
于 2010-12-02T14:55:43.387 回答
3

好吧,您可以检查类型是否有一个名为iterator_categoryThis can be done using的嵌套 typedef SFINAE,并且可以在wiki 页面中SFINAE找到确切的技术。这不是 100% 的方法,但所有体面的迭代器都应该为迭代器提供通用的 typedef,而 iterator_category 是迭代器独有的。也不要忘记检查 TYPE 是否只是一个指针。指针是迭代器。

于 2010-12-02T14:24:01.377 回答
2

原始海报澄清说,他们实际上是在寻求一种识别 InputIterator 的方法(请参阅http://en.cppreference.com/w/cpp/concept/InputIterator),因为他们希望能够增加和取消引用迭代器。这在标准 C++11 中有一个非常简单的 SFINAE 解决方案,例如类似于 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) { /* ... */ };

这依赖于迭代器类型特征类,它定义了 Armen Tsirunyan 认为迭代器本身需要的 typedef。(迭代器可以提供这些类型定义,但它们也可以在特征类中提供它们,这是使用裸指针作为迭代器所必需的,并且需要标准库实现。)

于 2016-10-24T20:05:20.373 回答
1
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 { };
于 2012-07-18T06:51:53.177 回答