如何SFINAE输出非容器参数

vso*_*tco 6 c++ templates sfinae c++11

我有一个模板函数,我想只为标准容器(或与标准容器兼容的容器,至少提供begin()成员函数)启用.我是SFINAE以下列方式输出非容器:

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
}
Run Code Online (Sandbox Code Playgroud)

std::is_samedecltype看起来不太优雅.有没有更好的方法呢?

PS:我需要SFINAE,因为我有不同的超载

template<typename Derived>
f(const Eigen::MatrixBase<Derived>& A)
Run Code Online (Sandbox Code Playgroud)

每当我尝试时f(some_Eigen_matrix),Container重载最终被拾取,然后编译器会发出错误,因为缺少类型begin().

Bar*_*rry 7

使用void_t,我们可以为拥有begin()end()(以及您可能想要检查的任何其他内容,例如typename T::iterator,您可以保持打桩表达式)创建一个类型特征:

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 { };
Run Code Online (Sandbox Code Playgroud)

然后就是SFINAE:

template <typename Container>
typename std::enable_if<
    is_std_container<Container>::value,
    typename Container::value_type
>::type 
f(const Container& c) { .. }
Run Code Online (Sandbox Code Playgroud)

另外,如果你真的想验证begin()能给你一个T::iterator(或至少它们是相等的),你也可以这样做:

void_t<
    decltype(begin(std::declval<T&>()) == std::declval<typename T::iterator>())
>
Run Code Online (Sandbox Code Playgroud)