The inner call to ranges::to
here isn't really what the point of ranges::to
is:
auto converted = text
| std::views::split('|')
| std::views::transform([](auto r) {
return r | std::ranges::to<my_data>(); // <== this one
})
| std::ranges::to<std::vector>();
It's true that, on some level, you're taking a range of char
and converting it into my_data
. But like - my_data
isn't any kind of range, so it's kind of weird from a design perspective. The name of that function can really be... anything. Indeed you could just spell it:
auto converted = text
| std::views::split('|')
| std::views::transform(stream_into<my_data>); // <== this one
| std::ranges::to<std::vector>();
Providing a:
template <typename T>
inline constexpr auto stream_into = [](std::span<char const> s) -> T {
T obj;
std::ispanstream(s) >> obj;
return obj;
};
And now you have a generic extracter, with a spelling that's more reflective of the actual operation being performed.
Either way, note that:
views::transform([](auto r){ return r | std::ranges::to<my_data>(); })
can be spelled as:
views::transform(std::ranges::to<my_data>())
This is the general property of range adaptor closure objects: R | C
and C(R)
are equivalent, so [](auto r) { return r | c; }
has the same meaning as c
.