1

I have this code: (live eg: https://godbolt.org/z/js1qK9hd1)

struct big_class
{
    std::string s1;
    std::string s2;
    std::string s3;
    std::string s4;
    std::string s5;
    std::string s6;
    std::string s7;
};

void func(const big_class &bc)
{
    std::cout << bc.s1 << bc.s2 << bc.s3 << bc.s4 << bc.s5 << bc.s6 << bc.s7 << std::endl;
}

void fwd_func(big_class &&bc)
{
    func(std::forward<big_class>(bc));
}

template<typename T>
void prefect_fwd_func(T &&bc)
{
    func(std::forward<T>(bc));
}

int main()
{
    big_class bc{"1", "2", "3", "4", "5", "6", "7"};

    std::cout << "func" << std::endl;
    func(bc);
    std::cout << "fwd_func" << std::endl;
    fwd_func(bc);
    std::cout << "perfect_fwd_func" << std::endl;
    prefect_fwd_func(bc);
}

So here fwd_func does not work - but in my mind its basically the same as the template perfect_fwd_func - only its not a template.

Why does this not work? - it says it can't bind lval to rval. I think its something to do with the template T && decaying into a T or something, but still can't quite puzzle it together... What is the difference between the two?

If I wanted to just pass a big_class type around - then I assume my best bet is to just pass it by const reference...

code_fodder
  • 15,263
  • 17
  • 90
  • 167
  • 2
    related/dupe: https://stackoverflow.com/questions/3582001/what-are-the-main-purposes-of-using-stdforward-and-which-problems-it-solves – NathanOliver Jun 16 '21 at 19:42
  • @NathanOliver its definitely related - but I don't think its quite a dup (though I will certainly be reading that), I am asking specifically the difference between `T&&` and `type&&`... but I am sure there are dups out there, I just did not find them yet :p – code_fodder Jun 16 '21 at 20:52

1 Answers1

3

Unlike big_class&&, which is a rvalue reference and can only take in an rvalue reference, the template version T&& is a universal reference / forwarding reference.

When you pass in something into the template function, T&& might be deduced to either an rvalue reference (big_class&&), or an lvalue reference (big_class&).

So it could generate 2 different functions for a single type U:

void prefect_fwd_func<U>(U&& bc);

and

void prefect_fwd_func<U&>(U& bc);

Go back to your code:

fwd_func(bc);

Here bc can not be passed as an rvalue reference, it can only be passed as either a value or an lvalue reference.

To fix it, you can either create a separate function that takes in big_class& as a parameter:

void fwd_func(big_class& bc){...}

Or, you can specifically move bc in the function call:

fwd_func(std::move(bc));

Or, create a temporary copy from bc:

fwd_func(big_class(bc));
Ranoiaetep
  • 5,872
  • 1
  • 14
  • 39