如何 SFINAE 输出非容器参数

How to SFINAE out non-containers parameters

我有一个模板函数,我只想为标准容器(或与标准容器兼容的容器,至少提供一个 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
}

std::is_samedecltype看起来不太优雅。有更好的方法吗?

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

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

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

使用 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 { };

然后就是 SFINAE:

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

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

void_t<
    decltype(begin(std::declval<T&>()) == std::declval<typename T::iterator>())
>