1

I tried to write some algorithm using recursive function and met this:

#include<vector>
using namespace std;
void f(vector<int>&& v) {
    if (!v.empty()) {
        // do some work
        v.pop_back();
        f(v); // compilation error!!!
    }
    return;
}

int main() {
    f(vector<int>{1, 2, 3});//ok
    return 0;
}

It doesn't compile, error message:

x86-64 clang 14.0.0
-std=c++11
<source>:7:9: error: no matching function for call to 'f'
        f(v);
        ^
<source>:3:6: note: candidate function not viable: expects an rvalue for 1st argument
void f(vector<int>&& v) {
     ^
1 error generated.

The reason I used "&&" is that I hope it could receive some r-value input parameter and use it as reference(not copy). I also tried to change f into generic function:

template<typename T>
void f(vector<T>&& v) {

Still fails.

How to fix this?

Troskyvs
  • 7,537
  • 7
  • 47
  • 115
  • 5
    A [rvalue reference is a lvalue](https://stackoverflow.com/questions/28483250/rvalue-reference-is-treated-as-an-lvalue), you need to use `f(std::move(v));`. – Sedenion Sep 07 '22 at 05:37
  • 1
    Inside `f`, `v` has a name and is therefore an l-value. Using `std::move(v)` will enable you to pass it recursivly to `f`. – wohlstad Sep 07 '22 at 05:43
  • 1
    This is probably the reduced essence of something else. (I know: MCVE. Thumbs up.) Nevertheless, I'm asking myself what you do with the moved `vector`. It will be filled in the nested calls of `f()` but then lost as soon as the recursion is terminated... ;-) – Scheff's Cat Sep 07 '22 at 05:49

1 Answers1

0

I have replaced

template<typename T>
void f(vector<T>&& v) {

By

template<typename T> void f(T&& v)

In your case it's a rvalue reference and in the second case it's a forwarding-reference (sometime call universal reference)

Demo : https://wandbox.org/permlink/ZbvOoB0kcyYPVzlq

In the line

    f(v); // compilation error!!!

v is an lvalue reference, so you have 2 choices :

  1. Transform it into a rvalue reference via an std::move like suggested in comment
  2. Allow f to works with lvalue reference. This can be done with forwarding-reference like in my example or by adding an overload for lvalue reference : void f(vector<int>& v). If you look at https://cppinsights.io/s/2f683e1c you will see that both code will do the same.
Martin Morterol
  • 2,560
  • 1
  • 10
  • 15
  • 1
    Why bother switching `typename` to `class`? – sweenish Sep 07 '22 at 05:38
  • does the same, my brain is just wired to type `class` – Martin Morterol Sep 07 '22 at 05:40
  • I think this code generates two different versions of `f` and one of them receives an `lvalue`, it's not quite same to the question. – Mer Sep 07 '22 at 07:45
  • 1
    @Mer It indeed create 2 versions (https://cppinsights.io/s/2f683e1c) but it respect the wish of OP to not create copy. Both version use reference, one R the other L-value reference – Martin Morterol Sep 07 '22 at 09:00
  • @MartinMorterol Ok, maybe you're right, it's a recursive function, we don't need to pass `rvalue` all the time – Mer Sep 07 '22 at 16:27