Ответ 1
В большинстве случаев должно быть достаточно следующего признака:
#include <type_traits>
#include <utility>
#include <iterator>
namespace detail
{
using std::begin;
using std::end;
template <typename T>
auto is_range_based_iterable(...)
-> std::false_type;
template <typename T
, typename I = typename std::decay<decltype(std::declval<T>().begin())>::type>
auto is_range_based_iterable(int)
-> decltype(std::declval<T>().begin()
, std::declval<T>().end()
, ++std::declval<I&>()
, void()
, std::integral_constant<bool,
std::is_convertible<decltype(std::declval<I&>() != std::declval<I&>()), bool>::value
&& !std::is_void<decltype(*std::declval<I&>())>::value
&& std::is_copy_constructible<I>::value
>{});
template <typename T
, typename I = typename std::decay<decltype(begin(std::declval<T>()))>::type>
auto is_range_based_iterable(char)
-> decltype(begin(std::declval<T>())
, end(std::declval<T>())
, ++std::declval<I&>()
, void()
, std::integral_constant<bool,
std::is_convertible<decltype(std::declval<I&>() != std::declval<I&>()), bool>::value
&& !std::is_void<decltype(*std::declval<I&>())>::value
&& std::is_copy_constructible<I>::value
>{});
}
template <typename T>
struct is_range_based_iterable : decltype(detail::is_range_based_iterable<T>(0)) {};
Тест:
#include <vector>
#include <array>
int main()
{
static_assert(is_range_based_iterable<std::vector<int>>::value, "!");
static_assert(is_range_based_iterable<std::array<int, 5>>::value, "!");
static_assert(is_range_based_iterable<int(&)[5]>::value, "!");
}