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

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

本文关键字:转换 用户 定义 类型 为什么 我可以      更新时间:2023-10-16

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

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

为什么删除的右值重载会阻止隐式转换为 int,但不能阻止从一个用户定义类型到另一个用户定义类型?

高完整性C++标准表明,右值参数 可以删除函数,从而防止隐式转换。

否,只有转发参考重载才会对重载集中的所有其他重载禁用 ICS(隐式转换序列(。使其成为转发引用,并查看禁用 ICS (Coliru 链接(

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

上面的代码将资格匹配添加到重载。因此,ICS仍在发挥作用。

foo(3.3)失败的原因是因为3.3double 类型的 prvalue,它与 rvalue 重载的匹配比转换为 int 更好。因为资格匹配的排名优于转换匹配

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

foo(a);
foo(3.3);

a是右值,3.3是右值。 右值参数与重载1匹配(仅接受右值(,左值参数不匹配。

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

有 3 种可能的重载

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

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

你可以看看 http://en.cppreference.com/w/cpp/language/overload_resolution查看所需的完整规则集