fork download
  1. #include <iostream>
  2. //First, some boilerplate to do easy argument dependent lookup of `begin` in a context where `std::begin` is visible:
  3.  
  4. #include <utility>
  5. #include <iterator>
  6. namespace adl_details {
  7. using std::begin; using std::end;
  8. template<class R>
  9. decltype(begin(std::declval<R>())) adl_begin(R&&r){
  10. return begin(std::forward<R>(r));
  11. }
  12. template<class R>
  13. decltype(end(std::declval<R>())) adl_end(R&&r){
  14. return end(std::forward<R>(r));
  15. }
  16. }
  17. using adl_details::adl_begin;
  18. using adl_details::adl_end;
  19. //This is required to reasonably emulate how range-based `for(:)` loops find their begin/end iterators. By packaging it up like this, we reduce boilerplate below.
  20.  
  21. //Next, some C++1y style utility aliases:
  22.  
  23. template<class>struct sink {using type=void;};
  24. template<class X>using sink_t=typename sink<X>::type;
  25. template<bool b, class T=void>using enable_if_t=typename std::enable_if<b,T>::type;
  26. //`sink_t` takes any type, and throws it away replacing it with `void`.
  27.  
  28. //`enable_if_t` removes annoying `typename` spam below.
  29.  
  30. //In an industrial strength library, we'd put this in `detail`s, and have a 1-type-argument version that dispatches to it. But I don't care:
  31.  
  32. template<class I,class=void> struct is_iterator:std::false_type{};
  33. template<> struct is_iterator<void*,void>:std::false_type{};
  34. template<> struct is_iterator<void const*,void>:std::false_type{};
  35. template<> struct is_iterator<void volatile*,void>:std::false_type{};
  36. template<> struct is_iterator<void const volatile*,void>:std::false_type{};
  37. template<class I>struct is_iterator<I,
  38. sink_t< typename std::iterator_traits<I>::value_type >
  39. >:std::true_type{};
  40. //`is_iterator` doesn't do heavy auditing of the `iterator_traits` of `I`. But it is enough.
  41.  
  42. template<class R>
  43. using begin_t=decltype(adl_begin(std::declval<R&>()));
  44. template<class R>
  45. using end_t=decltype(adl_end(std::declval<R&>()));
  46. //These two type aliases make the stuff below less annoying.
  47.  
  48. //Again, in industrial strength libraries, put 2-arg-with-`void` into `details`:
  49.  
  50. template<class R,class=void> struct has_iterator:std::false_type{};
  51. template<class R>
  52. struct has_iterator<
  53. R,
  54. enable_if_t<
  55. is_iterator<begin_t<R>>::value
  56. && is_iterator<end_t<R>>::value
  57. // && std::is_same<begin_t<R>,end_t<R>>::value
  58. >
  59. >:std::true_type{};
  60. //Note the commented out line in the `enable_if_t` above. I left that out to allow asymmetric iteration to work, where the `end` is a type that has a different `operator==` overload. Such is being considered for C++17: it allows really, really efficient algorithms on null-terminated strings (for example).
  61.  
  62. //Finally, the final output:
  63.  
  64. template<class R>using iterator_t=enable_if_t<has_iterator<R>::type, begin_t<R>>;
  65. //which evaluates to the iterator of the iterable range `R` iff it has one.
  66.  
  67. //There are cases where this won't work, but they are pathological.
  68.  
  69. int main() {
  70. int X[3];
  71. std::cout << has_iterator<decltype(X)>::value << "\n";
  72. begin_t<decltype(X)> x;
  73. std::cout << is_iterator<int*>::value << is_iterator<begin_t<decltype(X)>>::value << "\n";
  74. std::cout << is_iterator<void*>::value << "\n";
  75. std::cout << is_iterator<int>::value << "\n";
  76. return 0;
  77. }
Success #stdin #stdout 0s 3340KB
stdin
Standard input is empty
stdout
1
11
0
0