Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to SFINAE out non-containers parameters

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'm SFINAE-ing out non-containers in the following way:

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
}

The std::is_same and decltype don't look too elegant. Is there any better way of doing this?

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

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

and whenever I try f(some_Eigen_matrix), the Container overload ends up being picked up, then the compiler spits out an error because the type is lacking begin().

like image 212
vsoftco Avatar asked May 14 '15 18:05

vsoftco


1 Answers

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>())
>
like image 188
Barry Avatar answered Sep 19 '22 15:09

Barry