My understanding of overload resolution is that 'T&&' is generally a better match than 'const T&'. However, I'm seeing some inconsistent behavior among compilers with this trivial example:
#include <iostream>
void Func(const double& a)
{
(void)a;
std::cout << "[lvalue]\n";
}
void Func(double&& a)
{
(void)a;
std::cout << "[rvalue]\n";
}
template <typename T>
void TFunc(T&& a)
{
Func(a);
}
int main ()
{
TFunc(5.5f);
return 0;
}
Clang 3.2 will print [rvalue]. However, the VS2013 32bit/64bit compilers will print [lvalue]. If I change '5.5f' to '5.5', then both compilers will print [lvalue].
I can understand why the VS compiler chooses the 'const double&' version since I don't have a std::forward call to preserve the '&&' of the parameter. However, I still don't understand what makes clang think that the '&&' overload is the better choice.
Why does adding an implicit float to double conversion affect the behavior in clang? Who is right?
When you call with 5.5f
, T
is float, and the Func
call effectively becomes Func(double(a))
. The argument is a temporary, and so rvalue overload should be chosen.
When you call with 5.5
, T
is double, and no temporary is created in a call to Func(a)
. A named variable cannot bind to an rvalue reference, so lvalue overload is the only choice.
MSVC has a long-standing misfeature that allows temporaries to bind to non-const lvalue references. This is why it incorrectly chooses lvalue overload even in the first case. Try compiling with /Za
(disable language extensions) - I believe it would match clang's behavior then.
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