Übereinstimmungen mit iterierbaren Typen (Arrays und Klassen mit begin () / end ())
Ich habe Typmerkmale wie Klassen geschrieben, die verwendet werden können, um zu testen, ob ein bestimmter Typ "iterierbar" ist. Dies gilt für Arrays (zT[N]
, nicht fürT[]
) und für Klassen mit abegin
und einend
Methode, die Dinge zurückgibt, die wie Iteratoren aussehen. Ich frage mich, ob es präziser / einfacher geht als ich?
Besonders das Zeug in derimpl
Namespace sehen ein bisschen rund / hacky aus. Für mich sieht alles ein bisschen hässlich aus. Ein Beispiel, das dies verwendet und mit g ++ und clang ++ kompiliert werden kann, finden Sie unter:https://gist.github.com/panzi/869728c9879dcd4fffa8
template<typename T>
struct is_iterator {
private:
template<typename I> static constexpr auto test(void*)
-> decltype(
*std::declval<const I>(),
std::declval<const I>() == std::declval<const I>(),
std::declval<const I>() != std::declval<const I>(),
++ (*std::declval<I*>()),
(*std::declval<I*>()) ++,
std::true_type()) { return std::true_type(); }
template<typename I> static constexpr std::false_type test(...) { return std::false_type(); }
public:
static constexpr const bool value = std::is_same<decltype(test<T>(0)), std::true_type>::value;
};
namespace impl {
// implementation details
template<typename T>
struct has_iterable_methods {
private:
template<typename C> static constexpr auto test(void*)
-> decltype(
std::declval<C>().begin(),
std::declval<C>().end(),
std::true_type()) { return std::true_type(); }
template<typename C> static constexpr std::false_type test(...) { return std::false_type(); }
public:
static constexpr const bool value = std::is_same<decltype(test<T>(0)), std::true_type>::value;
};
template<typename T, bool HasIterableMethods>
struct returns_iterators : public std::false_type {};
template<typename T>
struct returns_iterators<T, true> {
typedef decltype(std::declval<T>().begin()) begin_type;
typedef decltype(std::declval<T>().end()) end_type;
static constexpr const bool value =
std::is_same<begin_type, end_type>::value &&
is_iterator<begin_type>::value;
};
}
template<typename T>
struct is_iterable : public std::integral_constant<
bool,
impl::returns_iterators<
typename std::remove_const<T>::type,
impl::has_iterable_methods<typename std::remove_const<T>::type>::value>::value> {};
template<typename T, std::size_t N>
struct is_iterable<T[N]> : public std::true_type {};
template<typename T>
struct is_iterable<T*> : public std::false_type {};