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?
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.
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