У меня в голове есть ментальная модель, согласно которой эти два выражения являются синонимами.
R | std::views::transform([](auto&& e) { return f(e); });
R | std::views::transform(f); // good, saves unnecessary lambda
Однако у меня есть противоположный случай божий болт
#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?@HolyBlackCat, моя вина, сейчас вставил код и обновил ссылку.
Вы также можете использовать BOOST_HOF_LIFT, например: std::views::transform(BOOST_HOF_LIFT(to_counter)). Вот демо.





Ты так думаешь
[](auto&& e) { return f(e); }
это лишнее, но на самом деле полезно. Он позволяет f быть не обязательно функтором, но и многим другим, включая набор перегруженных функций, шаблон функции или функцию из пространства имен std (которую стандарт C++ запрещает использовать непосредственно вместо функтора).
В качестве примечания: чтобы сохранить идеальную переадресацию, предусмотренную с помощью ссылки на пересылку (auto&&), вы должны использовать std::forward в своей лямбде:
[](auto&& e) { return f(std::forward<decltype(e)>(e)); }
Теперь вернемся к исходному коду.
Хотя ваш вопрос начинается со слов «Функторы не распознаны...», 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{};
Вы только что перешли на главную страницу godbolt.org, там нет кода. Пожалуйста, также вставьте полный код в сам вопрос.