簡體   English   中英

如何定義is_iterator類型特征?

[英]How to define is_iterator type trait?

  • 我正在嘗試編寫一個is_iterator<T>類型的特征。 T是迭代器類型時, is_iterator<T>::value == true否則is_iterator<T>::value == false

  • 到目前為止我嘗試了什么:


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 {};

現場演示


問:是否有更合適的方法來定義is_iterator類型特征而不是上面顯示的特征?

正如我在評論中所說,這里介紹的解決方案在某些實現中依賴於iterators_traits非可移植屬性。 根據C ++ 03和C ++ 11標准, iterator_traits僅為迭代器(以及指針的特殊情況)定義,因此任何其他用途都是未定義的行為。 具體來說,在SFINAE上下文中使用iterator_traits<T>::pointer並不能保證工作,因為實例化iterator_traits<T>將引用T::value_typeT::pointerT::iterator_category等,這些都發生在外面SFINAE不適用的“直接背景”。

C ++ 14 將修復 本應該解決的問題(它發生在使用DR 2408的C ++ 14之后),但是對於C ++ 11,定義is_iterator的安全方法是編寫一個檢查所有必需操作的特征迭代器必須定義。 所有迭代器都需要支持的唯一操作是operator*以及前后增量。 不幸的是,可能存在定義那些不是有效迭代器的操作的類型,因此編寫正確的特征非常困難。

如果std::iterator_traits<T>::pointer是不是指針的類型,則檢查失敗,例如,如果T = std::ostream_iterator<U>

我認為更好的測試可能是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 {};

我認為沒有必要檢查iterator_traits的嵌套typedef的任何特定屬性。 它應該足以檢查是否存在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;
}

不幸的是,這不能保證在C ++ 11中有效,但是C ++ 14會修復它(感謝Jonathan Wakely指出它)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM