I know algorithms (e.g. sort
) in ranges support projection, but it seems to me that there is no way to get that functionality for views...
Am I right?
As an example consider following working code:
#include <algorithm>
#include <ranges>
#include <vector>
#include <iostream>
enum Color {
Red,
Green,
Blue
};
struct Cat {
int age;
Color color;
};
int main() {
std::vector<Cat> cats{{.age = 10,.color=Color::Red}, {.age = 20,.color=Color::Blue}, {.age = 30,.color=Color::Green}};
auto is_red = [](const auto& cat) {return cat.color == Color::Red;};
for (const auto& cat: cats | std::views::filter(is_red)) {
std::cout << cat.age << std::endl;
}
}
Is there a way to remove the lambda and do something like:
for (const auto& cat: cats | std::views::filter(&Cat::color, Color::Red) {
note: my question is for member variable projection, but obviously in real code member function calls would be also needed.
Do C++ ranges support projections in views?
No (although range-v3 did†).
Is there a way to remove the lambda and do something like:
std::views::filter(&Cat::color, Color::Red)
That wouldn't really be how this would work with projections anyway. It would have been:
filter([](Color c){ return c == Color::Red; }, &Cat::color)
Which you can reduce this if you have an equals
that returns a predicate:
filter(equals(Color::Red), &Cat::color)
But adding projections to algorithms is kind of unnecessary. You can always provide a projection manually. Using Boost.Hof's appropriately-named proj
function adapter, which satisfies proj(p, f)(xs...) == f(p(xs)...)
(i.e. we're applying p
on each argument before passing them into f
):
filter(proj(&Cat::color, [](Color c){ return c == Color::Red; }))
or, shorter:
filter(proj(&Cat::color, _ == Color::Red))
Demo.
†Even in the range-v3 implementation, it's not that remove_if_view
had explicit support for projections. It's that the overload that took a projection manually composed the predicate for you as compose(pred, proj)
. In range-v3, compose(f, g)(xs...)
can mean either f(g(xs...))
or f(g(xs)...)
depending on how g
is invocable. So in this case, it's a projection rather than function composition. In Boost.Hof, there is are distinct compose
and proj
adaptors for the two cases.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With