Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inconsistent overload resolution with rvalue references

Tags:

c++

c++11

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?

like image 273
lhumongous Avatar asked Jul 31 '14 14:07

lhumongous


1 Answers

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.

like image 141
Igor Tandetnik Avatar answered Sep 28 '22 16:09

Igor Tandetnik