I have a template function that I want to enable only for standard containers (or containers compatible with standard containers, which at least provide a begin()
Using void_t, we can just make a type trait for having begin()
and end()
(and anything else you might want to check for, like typename T::iterator
, you can just keep piling expressions on):
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 that:
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 wanted to verify that begin()
gives you back a T::iterator
(or at least that they're equality comparable), you can do that too:
void_t<
decltype(begin(std::declval<T&>()) == std::declval<typename T::iterator>())
>