在我看来,我有这样的心理模型,认为这两个表达是同义词
R | std::views::transform([](auto&& e) { return f(e); });
R | std::views::transform(f); // good, saves unnecessary lambda
但是我有一个反例godbolt
#include <generator>
#include <map>
#include <ranges>
std::generator<int> to_prime_factors(int x) {
for (int i = 2; i < x; ++i) {
while (x % i == 0) {
co_yield i;
x /= i;
}
}
if (x > 1) {
co_yield x;
}
}
template <std::ranges::input_range R>
std::map<std::ranges::range_value_t<R>, int> to_counter(R&& range) {
std::map<std::ranges::range_value_t<R>, int> counter;
for (auto&& ele : range) {
counter[ele]++;
}
return counter;
}
int main() {
static_assert(
std::same_as<int, std::ranges::range_value_t<std::generator<int>>>);
auto as = std::views::iota(2, 6);
as | std::views::transform(to_prime_factors) |
std::views::transform([](auto&& factors) {
static_assert(std::ranges::input_range<decltype(factors)>);
return to_counter(factors); // stinky unnecessary lambda
});
as | std::views::transform(to_prime_factors) |
std::views::transform(to_counter); // oops
return 0;
}
从 GCC 日志中可以看出,它无法将最后一个表达式识别为部分适配器, 因为数量不匹配,但它也表明
Args = {}
这与我的期望不符,因为我已经通过了to_counter
。
问题:
to_counter
作为 transform_view
的参数?你这么认为
[](auto&& e) { return f(e); }
是多余的,但实际上很有用。它允许
f
不一定是函子,而是许多其他东西,包括一组重载函数、函数模板或命名空间 std 中的函数(C++ 标准禁止直接使用它来代替函子)。
虽然你的问题以“函子无法识别......”开头,但
to_counter
不是函子,甚至不是函数 - 它是一个函数模板。您可以用真正的函子替换 to_counter
的定义,即使用包含泛型 operator()
的类型的对象 - 然后一切都会编译:
inline struct {
template <std::ranges::input_range R>
std::map<std::ranges::range_value_t<R>, int> operator()(R&& range) {
std::map<std::ranges::range_value_t<R>, int> counter;
for (auto&& ele : range) {
counter[ele]++;
}
return counter;
}
} to_counter{};