Using void_t , we can simply create a type trait for begin() and end() (and anything else that you might need to check, for example, typename T::iterator , you can just save a bunch of expressions):
template <typename T, typename = void> struct is_std_container : std::false_type { }; template <typename T> struct is_std_container<T, void_t<decltype(std::declval<T&>().begin()), decltype(std::declval<T&>().end()), typename T::value_type >> : std::true_type { };
And then just SFINAE on this:
template <typename Container> typename std::enable_if< is_std_container<Container>::value, typename Container::value_type >::type f(const Container& c) { .. }
Also, if you really want to check that begin() returns a T::iterator (or at least the equality equivalent), you can also do this:
void_t< decltype(begin(std::declval<T&>()) == std::declval<typename T::iterator>()) >
Barry source share