Why can I prevent implicit conversions for primiti

2019-03-02 18:33发布

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?

3条回答
叛逆
2楼-- · 2019-03-02 18:56

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

No, only a forwarding reference overload disables ICS (Implicit Conversion Sequence) for all other overloads in the overload set. Make it a forwarding reference, and see ICS disabled (Coliru Link)

template <class T>
void foo(const T&&) = delete;  // introduces a qualification match

The above code adds a qualification match to the overload. Thus, ICS is still in play.

Why foo(3.3) failed is because 3.3 is an prvalue of type double which will match better with the rvalue overload than converting to int. Because qualification match is ranked better than a conversion match

查看更多
放我归山
3楼-- · 2019-03-02 18:59

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

查看更多
做自己的国王
4楼-- · 2019-03-02 19:10

There are 3 possible overloads

  • 1 is viable.
  • 2 is viable
  • 3 isn't

2 is better match (template (non exact match) vs regular method (with one user define conversion)).

You may look at http://en.cppreference.com/w/cpp/language/overload_resolution to see a complete set of rules needed

查看更多
登录 后发表回答