ericniebler / range-v3

Range library for C++14/17/20, basis for C++20's std::ranges
Other
4.11k stars 440 forks source link

An action::transform that might change types #1596

Open brevzin opened 3 years ago

brevzin commented 3 years ago

I have the following setup:

struct Widget {
    int weight;
    std::string name;
};
auto get_widgets() -> std::vector<Widget>

And I want to get a vector of the widget names. That seems like I should want this:

auto names = get_widgets() | actions::transform(&Widget::name);

But actions::transform doesn't let me change the element type, it's an in-place transform. So then it seems I might want this:

auto names = get_widgets() | views::transform(&Widget::name) | ranges::to<std::vector>();

But this doesn't work because get_widgets() isn't a viewable_range, despite it being consumed by this operation and so being perfectly safe. This leads me to having to write either:

auto widgets = get_widgets();
auto names = widgets | views::transform(&Widget::name) | ranges::to<std::vector>();

which takes an extra line and introduces an extra name, or add a helper somewhere like:

auto as_lvalue = [](auto&& v) -> auto& v { return v; };

to force get_widgets() to behave like a viewable_range:

auto names = as_lvalue(get_widgets())
    | views::transform(&Widget::name)
    | ranges::to<std::vector>();

Which just seems hacky.

It seems like there should be a better solution for this kind of transformation.

JohelEGP commented 3 years ago

Hacky and less performant by default. You probably want to add a move there.

CaseyCarter commented 2 years ago

But this doesn't work because get_widgets() isn't a viewable_range

Is this still true after merging P2415?

brevzin commented 2 years ago

But this doesn't work because get_widgets() isn't a viewable_range

Is this still true after merging P2415?

Yeah that'll work in C++23, but range-v3 is a bit divergent from ISO C++ at this point (with neither move-only nor non-default-constructible views).