How to check if an arbitrary type is an iterator?

前端 未结 3 575
伪装坚强ぢ
伪装坚强ぢ 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: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 
    #include 
    #include 
    #include 
    
    template 
      struct is_iterator {
      static char test(...);
    
      template ::difference_type,
        typename=typename std::iterator_traits::pointer,
        typename=typename std::iterator_traits::reference,
        typename=typename std::iterator_traits::value_type,
        typename=typename std::iterator_traits::iterator_category
      > static long test(U&&);
    
      constexpr static bool value = std::is_same())),long>::value;
    };
    
    struct Foo {};
    
    //Returns true
    bool f() { return is_iterator::iterator>::value; }
    //Returns true    
    bool fc() { return is_iterator::const_iterator>::value; }
    //Returns true
    bool fr() { return is_iterator::reverse_iterator>::value; }
    //Returns true
    bool fcr() { return is_iterator::const_reverse_iterator>::value; }
    //Returns true
    bool g() { return is_iterator::value; }
    //Returns true
    bool gc() { return is_iterator::value; }
    //Returns false
    bool h() { return is_iterator::value; }
    //Returns false
    bool i() { return is_iterator::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 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 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 for some type T and does not provide all of the required typedefs.

提交回复
热议问题