The error message is trying to convey:
A non-const
reference cannot bind to a temporary value because the temporary object's lifetime would have expired before the control reaches the function.
- The variable
ca
is not a temporary, because it has a name that can be referred to in main
.
- It's lifetime does not expire till the end of
main
, and so can be safely referenced from within wrapper
.
- Template type deduction does not drop
const
since it would be a violation of const
-correctness for ca
.
For wrapper(A());
, the type parameter T
would be deduced as A
. Since the temporary has no const
-ness, so the parameter u
would be deduced to a A&
, but a since non-const
reference cannot bind to a temporary value for the reason mentioned above, there is no wrapper
function that is viable to be called using the argument A()
.
Now, C++ features the extension of lifetime for a temporary object if you are only reading from it. This is the reason why const T&
binds to temporary objects. In your case the nameless temporary object's lifetime is extended till the end of the wrapper
function.
If you explicitly set the type parameter to be const T&
the following:
template <typename T>
void wrapper(const T& u)
{
g(u);
}
class A {};
void g(const A& a) {}
int main()
{
const A ca;
wrapper(ca);
wrapper(A()); // Error no more.
}
would compile just fine.
[C++11]
For wrapper(A());
, the type parameter T
would still be deduced as A
, and the parameter u
would be of type A&&
, called an rvalue reference to A
.
Suppose we add another overload to wrapper
so that the following:
template <typename T>
void wrapper(const T& u)
{
g(u);
}
template <typename T>
void wrapper(T&& u)
{
g(u);//u is an lvalue since it has a name.
}
exists.
You can expect wrapper(A());
to compile, preferring the rvalue overload, because the rvalue reference is an lvalue in wrapper
as it has a name.