I wrote type traits like classes that can be used test if a given type is \"iterable\". This is true for arrays (for T[N]
, not for T[]
) and for cla
First, some boilerplate to do easy argument dependent lookup of begin
in a context where std::begin
is visible:
#include
#include
namespace adl_details {
using std::begin; using std::end;
template
decltype(begin(std::declval())) adl_begin(R&&r){
return begin(std::forward(r));
}
template
decltype(end(std::declval())) adl_end(R&&r){
return end(std::forward(r));
}
}
using adl_details::adl_begin;
using adl_details::adl_end;
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.
Next, some C++1y style utility aliases:
templatestruct sink {using type=void;};
templateusing sink_t=typename sink::type;
templateusing enable_if_t=typename std::enable_if::type;
sink_t
takes any type, and throws it away replacing it with void
.
enable_if_t
removes annoying typename
spam below.
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:
template struct is_iterator:std::false_type{};
template<> struct is_iterator:std::false_type{};
template<> struct is_iterator:std::false_type{};
template<> struct is_iterator:std::false_type{};
template<> struct is_iterator:std::false_type{};
templatestruct is_iterator::value_type >
>:std::true_type{};
is_iterator
doesn't do heavy auditing of the iterator_traits
of I
. But it is enough.
template
using begin_t=decltype(adl_begin(std::declval()));
template
using end_t=decltype(adl_end(std::declval()));
These two type aliases make the stuff below less annoying.
Again, in industrial strength libraries, put 2-arg-with-void
into details
:
template struct has_iterator:std::false_type{};
template
struct has_iterator<
R,
enable_if_t<
is_iterator>::value
&& is_iterator>::value
// && std::is_same,end_t>::value
>
>:std::true_type{};
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).
Finally, the final output:
templateusing iterator_t=enable_if_t::type, begin_t>;
which evaluates to the iterator of the iterable range R
iff it has one.
There are cases where this won't work, but they are pathological.
live example