Transform Temporary Vector with Range-v3

760 Views Asked by At

I've been doing a lot of reading regarding range-v3 views, actions, and how they interact with temporary collections, but I still feel like I'm missing something simple that would help me accomplish what I feel like should work.

Given the following:

std::vector<int> get_vector() { return {1, 2, 3}; }

void func1()
{
  auto const v1 =
    get_vector() |
    ranges::view::transform([](auto const& i) { return i + 1; }) |
    ranges::to_vector;
}

I get an error message:

error: use of deleted function

And a nice message to read:

// **************************************************************************
// *    When piping a range into an adaptor, the range must satisfy the     *
// *    "viewable_range" concept. A range is viewable when either or both   *
// *    of these things are true:                                           *
// *      - The range is an lvalue (not a temporary object), OR             *
// *      - The range is a view (not a container).                          *
// **************************************************************************

Which makes sense, but I don't want to save the vector returned by get_vector into a named variable. I don't need it. I just want a new vector created by the transform and to_vector.

I don't like to assign temporaries to lvalues because I feel like it legitimizes them, and in my mind, after this one line of code, I want the temporary vector to destruct. I don't want the data to hang around. I don't want it to have a name. I don't want the next developer to accidentally think they can use it.

I think the part that gets me the most is that I feel like this should work. Passing temporaries to a function is bread-and-butter for C++. I guess since I'm not creating a view that I want to save per-say, range-v3 might be the wrong library for the job.

I tried several other combinations I've read. Such as ranges::views::cache1:

void func1()
{
  auto const v1 =
    get_vector() |
    ranges::views::cache1 |
    ranges::views::transform([](auto const& i) { return i + 1; }) |
    ranges::to_vector;
}

But get the same error. Other combinations I've tried with the same error:

void func1()
{
  auto const v1 =
    get_vector() |
    ranges::views::transform([](auto const& i) { return i + 1; }) |
    ranges::views::cache1 |
    ranges::to_vector;
}

And:

void func1()
{
  auto const v1 =
    get_vector() |
    ranges::views::cache1 |
    ranges::views::transform([](auto const& i) { return i + 1; }) |
    ranges::views::cache1 |
    ranges::to_vector;
}

I tried using an action, but got an error about:

// *    When piping a range into an action, the range must be moved in.     *

Which doesn't make as much sense to me, since the temporary vector is already an rvalue.

What am I missing? I'm just whack-a-moleing now.

1

There are 1 best solutions below

5
On

As the error message says, when piping a range into an adaptor, you need the range to be an l-value, or a view.

The temporary vector returned by get_vector doesn't fall into either of the above categories. One fix would be to assign it to an l-value, like this:

void func1()
{
    auto&& vec = get_vector();
    
    auto const v1 = 
      vec |
      ranges::views::transform([](auto const& i) { return i + 1; }) |
      ranges::to_vector;
}

Here's a demo.