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?
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With