为啥我可以阻止基元而不是用户定义类型的隐式转换?
Posted
技术标签:
【中文标题】为啥我可以阻止基元而不是用户定义类型的隐式转换?【英文标题】:Why can I prevent implicit conversions for primitives but not user-defined types?为什么我可以阻止基元而不是用户定义类型的隐式转换? 【发布时间】:2017-05-15 21:55:45 【问题描述】:高完整性 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 而不是从一种用户定义类型转换为另一种?
【问题讨论】:
MM 指出我的代码示例混淆了问题。 这句话的后半部分也不准确,“高完整性 C++ 标准建议可以删除函数的右值参数,从而防止隐式转换。”。可以删除 RValue 重载,但 HIPCC 并不建议这样做可以防止隐式转换。 【参考方案1】:高完整性 C++ 标准建议将右值参数 可以删除函数,从而防止隐式转换。
不,只有 转发引用 重载会为重载集中的所有其他重载禁用 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.3
是double
类型的prvalue,与转换为int
相比,它更适合右值重载。因为资格匹配是ranked better而不是转化匹配
【讨论】:
声明void foo(const B&&) = delete;
会阻止隐式转换。我的代码示例虽然混淆了问题。我会发布一个后续问题。
@jbcoe,是的,删除特定类型的 const
rvalue 重载也会禁用该类型的 ICS。但是删除 转发引用 重载会禁用整个重载集的 ICS。
谢谢。为什么函数和函数模板的行为不同?
删除转发引用过于激进,因为它会阻止使用非常量左值引用进行调用。
发布后续问题:***.com/questions/43995946/…【参考方案2】:
在您的代码中,用户定义类型和原始类型之间的处理方式没有区别。这两行的行为区别:
foo(a);
foo(3.3);
a
是左值,3.3
是右值。右值参数匹配你的重载1
(它只接受右值),左值参数不匹配。
如果您尝试使用右值参数调用 foo<A>
,它也会匹配 1
并失败,例如foo(A);
.
【讨论】:
你是对的。我对此有点困惑。为什么隐式转换也不匹配右值重载? (也许这值得在一个单独的问题中提出?) @jbcoe 在重载解析中,模板根据提供的参数进行实例化。 然后,在实例化和非模板函数之间发生重载决议(这涉及考虑隐式转换序列等)。 例如,在foo(a)
中,重载集是foo(B)
和foo(int)
- 没有可能的模板实例化a
作为参数。但是对于foo(3.3)
,重载集是foo<double>(const double&&)
、foo(B)
和foo(int)
。排名过程选择这三个中的第一个,因为直接引用绑定在浮点到整数转换之前排名
发布后续问题:***.com/questions/43995946/…【参考方案3】:
有 3 种可能的重载
1 是可行的。 2 是可行的 3 不是2 更好的匹配(模板(非精确匹配)与常规方法(使用一个用户定义转换))。
你可以看看http://en.cppreference.com/w/cpp/language/overload_resolution 查看所需的完整规则集
【讨论】:
以上是关于为啥我可以阻止基元而不是用户定义类型的隐式转换?的主要内容,如果未能解决你的问题,请参考以下文章