I can apply std::ranges::for_each
to a view and print each element line this:
#include <chrono>
#include <iostream>
#include <ranges> // views::transform, views::filter
#include <algorithm> // ranges::for_each
using namespace std; namespace c = std::chrono;
namespace v = std::views; namespace r = std::ranges;
int main() {
auto show_name = [](const string_view name) { cout << name << ' '; };
const auto& db = c::get_tzdb();
auto names = db.zones
| v::transform([](const c::time_zone& z) { return z.name(); })
| v::filter([](const string_view name) { return name.starts_with("Europe/Be"); });
r::for_each(names, show_name);
cout << " <- Europe/Be*\n";
}
But I would rather have something like this:
auto names = db.zones
| v::transform([](const c::time_zone& z) { return z.name(); })
| v::filter([](const string_view name) { return name.starts_with("Europe/Be"); });
| v::for_each(show_name);
cout << " <- Europe/Be*\n";
But I believe there is no std::views::for_each()
, right?
https://en.cppreference.com/w/cpp/ranges
I tried with views::transform([](n) { cout << n; return 0; }
but because of "lazy", that does nothing.
Also, I tried something like
cout << (db.zones
| v::transform([](const c::time_zone& z) { return z.name(); })
| v::filter([](const string_view name) { return name.starts_with("Europe/Be"); });
| v::join) << "\n";
But I believe that is not how join
works.
There is no such utility in the standard.
However, thanks to pipe support for user-defined range adaptors
, you can easily create one through ranges::range_adaptor_closure
in C++23:
#include <ranges>
#include <algorithm> // for ranges::for_each
namespace pipe {
namespace detail {
template<class F>
class for_each_closure : public std::ranges::range_adaptor_closure<for_each_closure<F>> {
F fun_;
public:
for_each_closure(F fun) : fun_(std::move(fun)) { }
template<std::ranges::input_range R>
constexpr auto operator()(R&& r) const {
return std::ranges::for_each(std::forward<R>(r), fun_);
}
};
}
template<class F>
constexpr auto for_each(F fun) {
return detail::for_each_closure<F>(std::move(fun));
}
};
Then you can use it like this
auto show_name = [](const string_view name) { cout << name << ' '; };
const auto& db = c::get_tzdb();
auto result = db.zones
| v::transform([](const c::time_zone& z) { return z.name(); })
| v::filter([](const string_view name) { return name.starts_with("Europe/Be"); })
| pipe::for_each(show_name);