Like SFINAE from options other than containers

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() member function). I get an exception from containers as follows:

 template<typename Container> typename Container::value_type f(const Container& c, typename std::enable_if< std::is_same< decltype(*c.begin()), typename Container::value_type >::value >::type* = nullptr) { // implementation here } 

std::is_same and decltype do not look too elegant. Is there a better way to do this?

PS: I need SFINAE here because I have a different overload

 template<typename Derived> f(const Eigen::MatrixBase<Derived>& A) 

and whenever I try to execute f(some_Eigen_matrix) , the Container overload ends, and then the compiler throws an error because begin() not in the type.

+6
source share
1 answer

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>()) > 
+6
source

Source: https://habr.com/ru/post/987221/


All Articles