如何 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_same
和decltype
看起来不太优雅。有更好的方法吗?
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>())
>
我有一个模板函数,我只想为标准容器(或与标准容器兼容的容器,至少提供一个 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_same
和decltype
看起来不太优雅。有更好的方法吗?
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>())
>