I'm trying to get my head around perfect forwarding in C++, and so I've written the following quick and dirty bit of code to test this.
class CValue
{
public:
CValue(int i) :
m_i(i)
{
printf("Default constructor called!\r\n");
}
CValue(const CValue& src) :
m_i(src.m_i)
{
printf("Copy constructor called!\r\n");
}
CValue(CValue&& src) :
m_i(src.m_i)
{
printf("Move constructor called!\r\n");
}
CValue& operator=(const CValue& src)
{
m_i = src.m_i;
printf("Copy assignment called!\r\n");
return *this;
}
CValue& operator=(CValue&& src)
{
m_i = src.m_i;
printf("Move assignment called!\r\n");
return *this;
}
int m_i;
};
template <typename T>
void PerfectForwarding(T&& tValue)
{
T tValue1 = tValue;
tValue1.m_i = 10;
}
int _tmain(int argc, _TCHAR* argv[])
{
CValue v(0);
PerfectForwarding(v);
printf("%d\r\n", v.m_i);
return 0;
}
When I build and run this code as a console application I get the answer 10, when I was expecting 0.
It seems that the line:
T tValue1 = tValue;
in the PerfectForwarding function is being resolved to:
CValue& tValue1 = tValue;
instead of:
CValue tValue1 = tValue;
So the compiler is resolving T to be CValue&, which I didn't expect.
I tried invoking the function from _tmain by explicitly declaring the template parameter type, i.e.
PerfectForwarding<CValue>(v);
but this fails to compile with the following error:
error C2664: 'void PerfectForwarding<CValue>(T &&)' : cannot convert
argument 1 from 'CValue' to 'CValue &&'
with
[
T=CValue
]
You cannot bind an lvalue to an rvalue reference
I can force the desired behaviour through changing the line in the PerfectForwarding function to the following:
typename std::remove_reference<T>::type tValue1 = tValue;
but I didn't think this should be necessary. By the reference collapsing rules the type of the argument (T&&) should become CValue& (as T&& & -> T&), but T itself should be simply CValue, surely? Is this a bug in the VC12 compiler's handling of rvalue references, or am I misunderstanding something about rvalue references and templates?
I'm using Visual Studio 2013 (VC12 compiler) in debug with all optimisation turned off.