Skip to content

Instantly share code, notes, and snippets.

@Astro36
Last active March 29, 2020 14:17
Show Gist options
  • Save Astro36/c56255e55d3da2a418b0faff161b72dc to your computer and use it in GitHub Desktop.
Save Astro36/c56255e55d3da2a418b0faff161b72dc to your computer and use it in GitHub Desktop.
Check if arbitrary type can use for-each loop by using C++ SFINAE
#include <iterator>
#include <type_traits>
template<typename T, typename = void>
struct is_iterable : std::false_type {};
template<typename T>
struct is_iterable<T, std::void_t<decltype(*std::begin(std::declval<T&>()) != *std::end(std::declval<T&>())),
decltype(++std::declval<decltype(std::begin(std::declval<T&>()))&>())>> : std::true_type {};
template<typename T>
inline constexpr bool is_iterable_v = is_iterable<T>::value;
/**
* @tparam I iterable
*/
template<typename I>
using iterator_type = decltype(*std::begin(std::declval<I&>()));
/**
* Check if `I` is Iterable<T>.
* @tparam I iterable
* @tparam T iterator type
*/
template<typename I, typename T>
concept Iterable1D = is_iterable_v<I&> && std::is_convertible_v<iterator_type<I>, T>;
/**
* Check if `I` is Iterable<Iterable<T>>.
* @tparam I iterable
* @tparam T iterator type
*/
template<typename I, typename T>
concept Iterable2D = is_iterable_v<I> && Iterable1D<iterator_type<I>, T>;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment