为什么我可以防止基元的隐式转换而不防止用户定义的类型?

时间:2017-05-15 21:55:45

标签: c++ rvalue overload-resolution

高完整性C ++标准建议可以删除函数的rvalue参数,从而防止隐式转换。

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

我发现原语和用户定义类型的行为非常不同。

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

为什么删除的rvalue重载会阻止隐式转换为int而不是从一个用户定义的类型转换为另一个?

3 个答案:

答案 0 :(得分:2)

  

高完整性C ++标准建议使用rvalue参数   可以删除函数,从而防止隐式转换。

不,只有转发引用重载会对重载集中的所有其他重载禁用ICS (Implicit Conversion Sequence)。将其作为转发参考,并see ICS disabled (Coliru Link)

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

以上代码为重载添加了限定匹配。因此,ICS仍然在发挥作用。

为什么foo(3.3)失败是因为3.3double类型的 prvalue ,它与rvalue重载匹配比转换为int更好。因为资格匹配ranked better而不是转换匹配

答案 1 :(得分:1)

有3种可能的重载

  • 1是可行的。
  • 2是可行的
  • 3不是

2更好匹配(模板(非完全匹配)与常规方法(一个用户定义转换))。

您可以查看http://en.cppreference.com/w/cpp/language/overload_resolution 查看所需的一整套规则

答案 2 :(得分:1)

在您的代码中,用户定义类型和基本类型之间的处理没有区别。这两行的行为之间的区别:

foo(a);
foo(3.3);

a是左值,3.3是左值。 rvalue参数匹配您的重载1(只接受rvalues),而lvalue参数不匹配。

如果您尝试使用rvalue参数调用foo<A>,它也会匹配1并失败,例如foo(A{});