Overload ambiguity when passing R-value to function that takes L-value

c++, c++11, rvalue-reference

Solution

Short version: Try updating your compiler. Your version doesn't implement http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1164 .

Your second template is a "perfect forwarding" template. Any function template parameter of type `T&&`, where `T` is a template parameter will deduce that template parameter to `X` (where `X` is the argument type) when the argument is an rvalue, and to `X&` if the argument is an lvalue.

In your case you passed an rvalue, so `T` was deduced to `Obj` (and `int` in your real code). If you would have passed a variable name or something else that is an lvalue, your second template would have the parameter type `Obj&` (T would be `Obj&`, and `&&` applied to such a type stays `Obj&`).

But the other template also has such a parameter type. So during overload resolution the conversion of the argument to the parameter is the same (perfect match), and another criteria needs to inspected, the specifity of the two templates, under the partial ordering rule. If one template is more specialized than the other template, then it will be chosen by the compiler. If there is no template more specialized than the other one, a final ambiguity is risen.

In this case, the first template is more specialized than the second template, and hence the compiler should call the first template finally.

Problem

I have 2 overloaded functions - one takes an L-value, and the other takes an R-value. The purpose is so that the function can be called like: ``` Obj obj; foo(obj); ``` OR: ``` foo(Obj()); ``` So, I write 2 overloaded functions: ``` template <class T> void foo(T& v) { /* ... function body code goes here ... */ } template <class T> void foo(T&& v) { foo(v); } int main() { foo(int(5)); } ``` The R-value overload merely needs to delegate to the L-value overload. The way I understand it, once I'm in the body of the function, any use of `v` gives me an L-value reference, unless I specifically use `std::move` or `std::forward`. So calling `foo(v)` within the R-value overload should automatically call the L-value version (rather than recursing.) But, the compiler complains about ambiguity: ``` test.cpp: In function ‘void foo(T&&) [with T = int]’: test.cpp:305:12: instantiated from here test.cpp:299:2: error: call of overloaded ‘foo(int&)’ is ambiguous ``` I don't understand why this is ambiguous. The call to `foo()` within the R-value overload should clearly call the L-value version. So why doesn't this compile?

Original source

Related problems