How to check if a template parameter is an iterator type or not?

匿名 (未验证) 提交于 2019-12-03 01:27:01

问题:

template struct is_iterator {     static const bool value = ??? // What to write ??? };  int main() {     assert(false == is_iterator::value);     assert(true == is_iterator::iterator>::value);     assert(true == is_iterator::iterator>::value);     assert(true == is_iterator<:iterator>::value);     assert(true == is_iterator::value); // a raw pointer is also an iterator } 

The question is: How to make the five assert statements pass?

回答1:

template struct is_iterator {        static T makeT();     typedef void * twoptrs[2];  // sizeof(twoptrs) > sizeof(void *)     static twoptrs & test(...); // Common case     template static typename R::iterator_category * test(R); // Iterator     template static void * test(R *); // Pointer      static const bool value = sizeof(test(makeT())) == sizeof(void *);  }; 


回答2:

Coming in here a few years later, where C++11 and C++14 make it a lot easier to do such things. An iterator is, at its core, something that is dereferencable, incrementable. If it's an input iterator, then also comparable. Let's go with the latter - since that looks like what you want.

The simplest version would be to use void_t:

template  using void_t = void; 

Base case:

template  struct is_input_iterator : std::false_type { }; 

Valid case specialization:

template  struct is_input_iterator()),                       // incrementable,            decltype(*std::declval()),                        // dereferencable,            decltype(std::declval() == std::declval())>>  // comparable     : std::true_type { }; 

Alias:

template  using is_input_iterator_t = typename is_input_iterator::type; 

No need to rely on iterator_category or using the tedious C++03 style of check things using overload resolution. Expression SFINAE is where it's at.


As Mr. Wakely points out in the comments, [iterator.traits] requires that:

it is required that if Iterator is the type of an iterator, the types

iterator_traits::difference_type iterator_traits::value_type iterator_traits::iterator_category 

be defined as the iterator’s difference type, value type and iterator category, respectively.

So we can define our iterator trait to simply check for that:

template  struct is_iterator : std::false_type { };  template  struct is_iterator::iterator_category >> : std::true_type { }; 

If iterator_traits::iterator_category is ill-formed, then T is not an iterator.



回答3:

Well, you could check for the type to have a nested typedef called iterator_category This can be done using SFINAE, and the exact technique can be found in wiki page for SFINAE. This isn't a 100% method, but all decent iterators should provide the common typedefs for iterators, and the iterator_category is one that is unique to iterators. Also don't forget to check if TYPE is simply a pointer. Pointers are iterators.



回答4:

template  struct is_iterator : public boost::false_type { };  template  struct is_iterator::type > : public boost::true_type { }; 


回答5:

The original poster clarified that they are actually asking for a way to identify an InputIterator (see http://en.cppreference.com/w/cpp/concept/InputIterator) because they want to be able to increment and dereference the iterator. This has a very simple SFINAE solution in standard C++11, e.g. similar to that from the gcc STL:

template using RequireInputIterator = typename     std::enable_if<:is_convertible std::iterator_traits="">::iterator_category,                                        std::input_iterator_tag>::value>::type;  ...  // Example: declare a vector constructor from a pair of input iterators. template  >     MyVector(InputIterator first, InputIterator last) { /* ... */ }; 

This relies on the iterator type traits classes, which define the typedefs that Armen Tsirunyan thought were required of the iterators themselves. (The iterators can provide those typedefs, but they can also provide them in traits classes, which is necessary in order to use naked pointers as iterators, and the standard library implementations are required to do so.)



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!