I would like to apply a projection prior to piping a range into an action or view. Consider the following example:
#include <iostream>
#include <range/v3/view/map.hpp>
#include <range/v3/action/sort.hpp>
#include <range/v3/algorithm/for_each.hpp>
int main()
{
std::vector<std::string> strings{"1.2","100.2","11.2","0.2","2.2"};
ranges::for_each(strings, [](const auto& str) { std::cout << str << std::endl; });
strings | ranges::views::all | ranges::actions::sort;
std::cout << std::endl;
ranges::for_each(strings, [](const auto& str) { std::cout << str << std::endl; });
return 0;
}
Say that I wish to convert the string to a double prior to sorting. Using the functional approach, this is possible:
strings |= ranges::actions::sort(std::less{}, [](const auto& str) { return std::stod(str); });
However I'm wondering if there is a pipeline format which allows this instead, which applies this projection for all following operations, for example:
strings | ranges::views::projection([](const auto&str ) { return std::stod(str); }) | ranges::actions::sort;
Note that using ranges::views::transform
doesn't work as it creates a new range instead of a projection.
I'm also not sure if there's a caveat for using strings | ranges::views::all | ranges::actions::sort
instead of strings |= ranges::actions::sort
which is recommended in the range-v3 documentation.
Update(2021.01.26):
Doing actions on projected views might cause confusion. E.g. imagine a projection function with signature int&(std::pair<int, int>&) / int&&(std::pair<int, int>&&)
that return the first component of a pair, apply that projection on a range of std::pair<int, int>
. What should happen if we filter
?
int
because we passed it a range of int
.std::pair<int, int>
because we really want to filter the underlying range of std::pair<int, int>
.But it does not know we want which.
So it seems that it is not appropriate to treat projection as a standalone operation on range this time, instead it is more clear if the projection operation is an optional parameter of filter or sort.
Old answer(2021.01.15):
It is inefficient to implement sorting with projection and perhaps that's why it's not provided. You have to store the result of projection explicitly:
c++ - Why can't a range be sorted in range-v3? - Stack Overflow
Why can't a range be sorted in range-v3?
The standard version says the complexity of projection is 𝓞(N·log(N)) (so it may be faster to project the elements and store them before sorting):
std::ranges::sort - cppreference.com
https://en.cppreference.com/w/cpp/algorithm/ranges/sort