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
}
问题是:如何使五个断言语句通过?
答案 0 :(得分:11)
几年后来到这里,C ++ 11和C ++ 14使这些事情变得容易多了。 iterator的核心是不可改变的,可递增的。如果它是input iterator,那么也可以比较。让我们选择后者 - 因为这看起来像你想要的。
最简单的版本是使用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
不是迭代器。
答案 1 :(得分: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 *);
};
答案 2 :(得分:2)
好吧,您可以检查类型是否具有名为iterator_category
的嵌套typedef这可以使用SFINAE
来完成,并且可以在wiki page for SFINAE
中找到确切的技术。这不是一个100%的方法,但是所有体面的迭代器都应该为迭代器提供公共的typedef,而iterator_category是迭代器独有的。另外不要忘记检查TYPE是否只是一个指针。指针是迭代器。
答案 3 :(得分: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 { };
答案 4 :(得分:1)
原始海报澄清说他们实际上是在寻找一种识别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) { /* ... */ };
这依赖于迭代器类型traits类,它定义了Armen Tsirunyan认为迭代器本身需要的typedef。 (迭代器可以提供那些typedef,但它们也可以在traits类中提供它们,这对于使用裸指针作为迭代器是必需的,并且标准库实现需要这样做。)< / p>