Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

passing rvalue raises cannot bind to lvalue

The program is as below:

#include <iostream>
using namespace std;

template <typename F, typename T1, typename T2>
void flip2(F f, T1 &&t1, T2 &&t2)
{
      f(t2, t1);
}

void g(int &&i, int &j)
{
      cout << i << " " << j << endl;
}

int main(void)
{
      int i = 1;
      flip2(g, i, 42);
}

The compiler complains:

error: rvalue reference to type 'int' cannot bind to lvalue of type 'int'

But to my understanding, as T2 is instantiated with int, then the type of t2 is int&&, so it should be allowed to pass to function g's first argument (int &&).

What's wrong with my understanding?

like image 473
Charles0429 Avatar asked Jul 27 '16 05:07

Charles0429


1 Answers

f(t2, t1);

t2 has a name, so it is an lvalue. It's type is rvalue, but in an expression it's type is an lvalue. In order to pass it as an rvalue reference, you need to use std::forward (move or casting would be inappropriate here, because T1 and T2 are actually universal references, not rvalue references, see edit).

#include <iostream>
using namespace std;

template <typename F, typename T1, typename T2>
void flip2(F f, T1 &&t1, T2 &&t2)
{
      f(std::forward<T2>(t2), std::forward<T1>(t1));
}

void g(int &&i, int &j)
{
      cout << i << " " << j << endl;
}

int main(void)
{
      int i = 1;
        flip2(g, i, 42);
}

http://ideone.com/Aop2aJ

--- Why ---

Consider:

template<typename T>
void printAndLog(T&& text) {
    print(text);
    log(text);
}

int main() {
    printAndLog(std::string("hello, world!\n"));
}

When you use a variable's name, the expression-type is lvalue (glvalue?); the rvalueness is discarded. Otherwise in the example above, we'd have lost text to print(). Instead, we have to be explicit when we want to our rvalue to behave like one:

template<typename T>
void printAndLog(T&& text) {
    print(text);
    log(std::forward<T>(text));  // if text is an rvalue, give it up.
}

--- Edit ---

I used std::forward because T1&& and T2&& are universal references, not rvalue references. https://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers

like image 82
kfsone Avatar answered Sep 19 '22 02:09

kfsone