How to check if an arbitrary type is an iterator?

前端 未结 3 559
伪装坚强ぢ
伪装坚强ぢ 2020-12-05 10:48

This is an exact duplicate of this question, except that accepted answer is wrong, so I ask it again:

How do you correctly check to see if

相关标签:
3条回答
  • 2020-12-05 11:31

    How about something like this?

    template<typename T, typename = void>
    struct is_iterator
    {
       static constexpr bool value = false;
    };
    
    template<typename T>
    struct is_iterator<T, typename std::enable_if<!std::is_same<typename std::iterator_traits<T>::value_type, void>::value>::type>
    {
       static constexpr bool value = true;
    };
    

    example:

    #include <iostream>
    #include <type_traits>
    #include <vector>
    
    template<typename T, typename = void>
    struct is_iterator
    {
       static constexpr bool value = false;
    };
    
    template<typename T>
    struct is_iterator<T, typename std::enable_if<!std::is_same<typename std::iterator_traits<T>::value_type, void>::value>::type>
    {
       static constexpr bool value = true;
    };
    
    int main()
    {
       static_assert(!is_iterator<int>::value, "ass");
       static_assert(is_iterator<int*>::value, "ass");
       static_assert(is_iterator<std::vector<int>::iterator>::value, "ass");
    }
    

    http://liveworkspace.org/code/7dcf96c97fd0b7a69f12658fc7b2693e

    0 讨论(0)
  • 2020-12-05 11:31

    I implemented this one some time ago:

    template <typename T>
    struct is_iterator {  
        template <typename U>
        static char test(typename std::iterator_traits<U>::pointer* x);
    
        template <typename U>
        static long test(U* x);
    
        static const bool value = sizeof(test<T>(nullptr)) == 1;
    };
    

    It compiles fine using your example. I can't test it on VC though.

    Demo here.

    0 讨论(0)
  • 2020-12-05 11:50

    I believe this should be a complete solution. Try it on http://gcc.godbolt.org and see the resulting assembly for the test functions.

    #include <type_traits>
    #include <iterator>
    #include <vector>
    #include <utility>
    
    template <typename T>
      struct is_iterator {
      static char test(...);
    
      template <typename U,
        typename=typename std::iterator_traits<U>::difference_type,
        typename=typename std::iterator_traits<U>::pointer,
        typename=typename std::iterator_traits<U>::reference,
        typename=typename std::iterator_traits<U>::value_type,
        typename=typename std::iterator_traits<U>::iterator_category
      > static long test(U&&);
    
      constexpr static bool value = std::is_same<decltype(test(std::declval<T>())),long>::value;
    };
    
    struct Foo {};
    
    //Returns true
    bool f() { return is_iterator<typename std::vector<int>::iterator>::value; }
    //Returns true    
    bool fc() { return is_iterator<typename std::vector<int>::const_iterator>::value; }
    //Returns true
    bool fr() { return is_iterator<typename std::vector<int>::reverse_iterator>::value; }
    //Returns true
    bool fcr() { return is_iterator<typename std::vector<int>::const_reverse_iterator>::value; }
    //Returns true
    bool g() { return is_iterator<int*>::value; }
    //Returns true
    bool gc() { return is_iterator<const int*>::value; }
    //Returns false
    bool h() { return is_iterator<int>::value; }
    //Returns false
    bool i() { return is_iterator<Foo>::value; }
    

    This implementation uses SFINAE and overloading precedence. test(U&&) always has higher precedence than test(...) so it will always be chosen if not removed by SFINAE.

    For an iterator type T, std::iterator_traits<T> has all of the above mentioned typedefs present so test(U&&) and test(...) are both overload candidates. Since test(U&&) has higher precedence, its always chosen.

    For a non-iterator type T, test(U&&) fails SFINAE because std::iterator_traits<T> does not have the nested typedefs. Therefore the only remaining candidate is test(...).

    Note that this trait will also fail if someone specializes std::iterator_traits<T> for some type T and does not provide all of the required typedefs.

    0 讨论(0)
提交回复
热议问题