为什么用整数类型约束 auto 会使其无法调用 views::filter?
Why does constraining auto with an integral type render it uninvocable for views::filter?
我写了一个简单的谓词,我想传递给 std::ranges::views::filter
:
struct even_fn {
constexpr
bool operator()(std::integral auto&& e) const noexcept {
return e % 2 == 0;
}
};
inline constexpr even_fn even;
示例用法:
using namespace std::ranges;
views::iota(1, 10) | views::filter(even);
这失败了,有一大堆错误,我想,最有意义的是:
note: the expression 'is_invocable_v<_Fn, _Args ...> [with _Fn = even_fn&; _Args = {std::__detail::__cond_value_type<int>::value_type&}]' evaluated to 'false'
但是,如果我从运算符中删除 std::integral
部分(只留下 auto&&
),代码将成功编译。这是为什么?当我们有约束仿函数时,这个 __cond_value_type
有什么特别之处?
这是因为 std::integral
不允许推导引用类型。
实际上,过滤器视图将使用类似这样的内容进行过滤:
filter_function(*it);
对于大多数范围类型,这将 return 元素的左值引用。
因为它发送了一个左值引用,所以调用你的函数的唯一方法是推导 int&
,所以引用折叠是这样工作的:int& && --> int&
。没有它,用左值调用你的函数是不可能的。
但是 int&
不是整数类型,因此你的错误!
那你怎么才能让你的过滤器工作呢?
只需删除转发引用并使用 const 左值引用:
struct even_fn {
constexpr
bool operator()(std::integral auto const& e) const noexcept {
return e % 2 == 0;
}
};
这样,当从 int 左值推导时,只需推导 int
即可使调用正常进行。
使用概念模板参数,可以使用更高阶的概念来使这种情况有效:
template<typename T, concept C>
concept forwarded = C<std::remove_cvref_t<T>>;
并像这样使用它:
struct even_fn {
constexpr
bool operator()(forwarded<std::integral> auto&& e) const noexcept {
return e % 2 == 0;
}
};
我写了一个简单的谓词,我想传递给 std::ranges::views::filter
:
struct even_fn {
constexpr
bool operator()(std::integral auto&& e) const noexcept {
return e % 2 == 0;
}
};
inline constexpr even_fn even;
示例用法:
using namespace std::ranges;
views::iota(1, 10) | views::filter(even);
这失败了,有一大堆错误,我想,最有意义的是:
note: the expression 'is_invocable_v<_Fn, _Args ...> [with _Fn = even_fn&; _Args = {std::__detail::__cond_value_type<int>::value_type&}]' evaluated to 'false'
但是,如果我从运算符中删除 std::integral
部分(只留下 auto&&
),代码将成功编译。这是为什么?当我们有约束仿函数时,这个 __cond_value_type
有什么特别之处?
这是因为 std::integral
不允许推导引用类型。
实际上,过滤器视图将使用类似这样的内容进行过滤:
filter_function(*it);
对于大多数范围类型,这将 return 元素的左值引用。
因为它发送了一个左值引用,所以调用你的函数的唯一方法是推导 int&
,所以引用折叠是这样工作的:int& && --> int&
。没有它,用左值调用你的函数是不可能的。
但是 int&
不是整数类型,因此你的错误!
那你怎么才能让你的过滤器工作呢?
只需删除转发引用并使用 const 左值引用:
struct even_fn {
constexpr
bool operator()(std::integral auto const& e) const noexcept {
return e % 2 == 0;
}
};
这样,当从 int 左值推导时,只需推导 int
即可使调用正常进行。
使用概念模板参数,可以使用更高阶的概念来使这种情况有效:
template<typename T, concept C>
concept forwarded = C<std::remove_cvref_t<T>>;
并像这样使用它:
struct even_fn {
constexpr
bool operator()(forwarded<std::integral> auto&& e) const noexcept {
return e % 2 == 0;
}
};