Search code examples
c++rvalueoverload-resolution

Why can I prevent implicit conversions for primitives but not user-defined types?


The High Integrity C++ Standards suggest that rvalue arguments to functions can be deleted thus preventing implicit conversions.

http://www.codingstandard.com/rule/8-3-4-define-delete-functions-with-parameters-of-type-rvalue-reference-to-const/

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?


Solution

  • 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{});.