The following code fails to compile:
#include <iostream>
using namespace std;
int add2(const int& x)
{
return x + 2;
}
template <typename T>
T add2T(T&& x) {
return add2(std::forward<T>(x));
}
int main(int argc, char** argv) {
int x = 0;
cout << "Add 2" << endl;
cout << add2(2) << endl;
cout << add2(x) << endl;
cout << "Add 2T" << endl;
cout << add2T(10) << endl;
cout << add2T(x) << endl;
return 0;
}
With this message:
main.cpp: In instantiation of 'T add2T(T&&) [with T = int&]':
main.cpp:26:20: required from here
main.cpp:12:16: error: cannot bind non-const lvalue reference of type 'int&' to an rvalue of type 'int'
return add2(std::forward<T>(x));
~~~~^~~~~~~~~~~~~~~~~~~~
I'm not sure why the compiler is trying to bind the non-const lvalue reference to an rvalue. The forward should decay into an lvalue reference anyways, right?
An lvalue reference can bind to an lvalue, but not to an rvalue.
Lvalues and rvalues are fundamental to C++ expressions. Put simply, an lvalue is an object reference and an rvalue is a value. The difference between lvalues and rvalues plays a role in the writing and understanding of expressions.
“r-value” refers to the data value that is stored at some address in memory. References in C++ are nothing but the alternative to the already existing variable. They are declared using the '&' before the name of the variable.
Such a reference is called an lvalue reference to a const value (sometimes called a reference to const or a const reference). In the above program, we bind const reference ref to modifiable lvalue x . We can then use ref to access x , but because ref is const, we can not modify the value of x through ref .
The problem is not related to forward.
In the call add2T(x)
, the deduced template argument T
is int&
. (Only in this way can T&&
be an lvalue reference type.) Thus the return type is also int&
. However, the operand of return
(namely add2(std::forward<T>(x))
) is an rvalue that cannot be used to initialize int&
. Hence the error message.
If you want to prevent the return type from becoming a reference type, you can apply std::decay_t
:
template <typename T>
std::decay_t<T> add2T(T&& x)
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