The High Integrity C++ Standards suggest that rvalue arguments to functions can be deleted thus preventing implicit conversions.
I've found that the behaviour for primitives and user-defined types is very different.
struct A { };
struct B { B(const A& ) {} };
template <class T>
void foo(const T&&) = delete; // 1 - deleted rvalue overload. const intentional.
void foo(B) {} // 2
void foo(int) {} // 3
int main(int argc, char* argv[])
{
A a;
foo(a); // This resolves to 2
foo(3.3); // This resolves to 1
foo(2); // This resolves to 3 (as expected).
}
Why does a deleted rvalue overload prevent an implicit conversion to int but not from one user-defined type to another?
In your code, there is no difference in treatment between user-defined types and primitive types. The difference between the behaviour of these two lines:
foo(a);
foo(3.3);
is that a
is an lvalue, and 3.3
is an rvalue. The rvalue argument matches your overload 1
(which only accepts rvalues), the lvalue argument does not.
If you try to invoke foo<A>
with an rvalue argument it will also match 1
and fail, e.g. foo(A{});
.