简体   繁体   English

如何定义is_iterator类型特征?

[英]How to define is_iterator type trait?

  • I'm trying to code a is_iterator<T> type trait. 我正在尝试编写一个is_iterator<T>类型的特征。 Where when T is an iterator type is_iterator<T>::value == true otherwise is is_iterator<T>::value == false . T是迭代器类型时, is_iterator<T>::value == true否则is_iterator<T>::value == false

  • What I tried so far: 到目前为止我尝试了什么:


template <class, class Enable = void> 
struct is_iterator : std::false_type {};

template <typename T> 
struct is_iterator<T, typename std::enable_if<std::is_pointer<typename
     std::iterator_traits<T>::pointer>::value>::type> : std::true_type {};

LIVE DEMO 现场演示


Q: Is there a more proper way to define a is_iterator type trait than the one displayed above? 问:是否有更合适的方法来定义is_iterator类型特征而不是上面显示的特征?

As I said in comments, the solutions presented here rely on non-portable properties of iterators_traits in some implementations. 正如我在评论中所说,这里介绍的解决方案在某些实现中依赖于iterators_traits非可移植属性。 According to the C++03 and C++11 standards, iterator_traits is only defined for iterators (and the special case of pointers) so any other use is undefined behaviour. 根据C ++ 03和C ++ 11标准, iterator_traits仅为迭代器(以及指针的特殊情况)定义,因此任何其他用途都是未定义的行为。 Specifically, using iterator_traits<T>::pointer in a SFINAE context isn't guaranteed to work, because instantiating iterator_traits<T> will refer to T::value_type , T::pointer , T::iterator_category etc. and that happens outside the "immediate context" where SFINAE doesn't apply. 具体来说,在SFINAE上下文中使用iterator_traits<T>::pointer并不能保证工作,因为实例化iterator_traits<T>将引用T::value_typeT::pointerT::iterator_category等,这些都发生在外面SFINAE不适用的“直接背景”。

C++14 will fix that was supposed to fix that (it happened post-C++14 with DR 2408 ), but for C++11 the safe way to define is_iterator is to write a trait that checks for all the required operations an iterator must define. C ++ 14 将修复 本应该解决的问题(它发生在使用DR 2408的C ++ 14之后),但是对于C ++ 11,定义is_iterator的安全方法是编写一个检查所有必需操作的特征迭代器必须定义。 The only operations that all iterators are required to support are operator* and pre- and post-increment. 所有迭代器都需要支持的唯一操作是operator*以及前后增量。 Unfortunately, there can be types that define those operations which are not valid iterators, so writing a correct trait is quite hard. 不幸的是,可能存在定义那些不是有效迭代器的操作的类型,因此编写正确的特征非常困难。

Your check fails if std::iterator_traits<T>::pointer is a type that is not a pointer, for instance if T = std::ostream_iterator<U> . 如果std::iterator_traits<T>::pointer是不是指针的类型,则检查失败,例如,如果T = std::ostream_iterator<U>

I think a better test might be whether std::iterator_traits<T>::iterator_category is either std::input_iterator_tag or a derived type, or std::output_iterator_tag . 我认为更好的测试可能是std::iterator_traits<T>::iterator_categorystd::input_iterator_tag还是派生类型,或std::output_iterator_tag

template <class, class Enable = void> struct is_iterator : std::false_type {};
template <typename T> 
struct is_iterator
<T, 
 typename std::enable_if<
    std::is_base_of<std::input_iterator_tag, typename std::iterator_traits<T>::iterator_category>::value ||
    std::is_same<std::output_iterator_tag, typename std::iterator_traits<T>::iterator_category>::value 
 >::type> 
 : std::true_type {};

I think there's no need to check for any particular property of iterator_traits 's nested typedefs. 我认为没有必要检查iterator_traits的嵌套typedef的任何特定属性。 It should be enough to check for mere presence of iterator_traits<T>::value_type (or any other nested typedef, for that matter), because every iterator has one. 它应该足以检查是否存在iterator_traits<T>::value_type (或任何其他嵌套的typedef),因为每个迭代器都有一个。

#include <type_traits>
#include <iostream>
#include <iterator>

template<typename>
struct void_ {
  typedef void type;
};
// remove typename spam below:
template<typename Discard>
using void_t=typename void_<Discard>::type;
template<typename T>
using decay_t=typename std::decay<T>::type;    

// stick helper types into details, so the interface
// for is_iterator is cleaner:
namespace details {
  template<typename T, typename Enable=void>
  sturct is_iterator : is_iterator2<T, Enable> {};

  // special case: void* is not an iterator
  // but T* specialization would pick it up
  // if there weren't the following:

  template<typename V>
  struct is_iterator<V*, decay_t<V>> : std::false_type {};

  // phase 2: SFINAE pass to std::iterator_traits test
  // valid in C++14, and in many C++11 compilers, except
  // for above void issue:
  template<typename, typename Enable = void>
  struct is_iterator2 : std::false_type {};

  template<typename T>
  struct is_iterator2<T, 
    void_t< typename std::iterator_traits<T>::value_type>
  > : std::true_type {};
}
template<typename T>
struct is_iterator : details::is_iterator<T> {};

int main()
{
    std::cout
        << is_iterator<int*>::value
        << is_iterator<double>::value;
}

Unfortunately this isn't guaranteed to work in C++11, but C++14 will fix it (thanks to Jonathan Wakely for pointing it out). 不幸的是,这不能保证在C ++ 11中有效,但是C ++ 14会修复它(感谢Jonathan Wakely指出它)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM