如何检查任意类型是否为迭代器?

Meh*_*dad 17 c++ iterator

这是这个问题的完全重复,除了接受的答案是错误的,所以我再问一遍:

如何正确检查给定类型T是否为迭代器?

我尝试解决它:

// Assume enable_if and is_same are defined
// (hoping for a solution that works for C++03 too)

template<class T>
class is_iterator
{
    static char (&test(...))[2];
    template<class U>
    static typename std::enable_if<
        !std::is_same<
            typename std::iterator_traits<T>::value_type,
            void
        >::value,
        char
    >::type test(U);
public:
    static bool const value = sizeof(test(0)) == 1;
};

struct Foo { };

int main()
{
    return is_iterator<Foo>::value;
}
Run Code Online (Sandbox Code Playgroud)

在Visual C++上碰巧失败了:

...\vc\include\xutility(373):
错误C2039 :: 'iterator_category'不是成员'Foo'

因为iterator_traits正在寻找value_typein 的定义Foo,其中(显然)不存在.

清楚,__if_exists是基于Visual C++的可能性,但我正在寻找一个便携式解决方案.

For*_*veR 14

这样的事怎么样?

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;
};
Run Code Online (Sandbox Code Playgroud)

例:

#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");
}
Run Code Online (Sandbox Code Playgroud)

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


Mat*_*nte 5

我相信这应该是一个完整的解决方案。在http://gcc.godbolt.org上试用它并查看测试功能的结果程序集。

#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; }
Run Code Online (Sandbox Code Playgroud)

此实现使用 SFINAE 和重载优先级。test(U&&)总是比test(...)它有更高的优先级,如果没有被 SFINAE 删除,它总是会被选择。

对于迭代器类型Tstd::iterator_traits<T>具有上述所有类型定义,test(U&&)并且test(...)都是重载候选者。由于test(U&&)具有更高的优先级,因此始终选择它。

对于非迭代器类型Ttest(U&&)SFINAE 失败,因为std::iterator_traits<T>没有嵌套的 typedef。因此唯一剩下的候选人是test(...)

请注意,如果有人专门std::iterator_traits<T>研究某种类型T并且没有提供所有必需的 typedef ,则此 trait 也会失败。