在C ++中,隐式转换序列中只允许一个用户定义的转换。对于该限制,是否有任何实际原因(从语言用户的角度来看)?
答案 0 :(得分:12)
在尝试匹配源和目标类型时,仅允许一个用户定义的转换限制搜索范围。只需要检查这两种类型以确定它们是否可转换(除非用户定义的转换)。
没有这个限制可能会在某些情况下导致歧义,甚至可能需要在其他情况下测试无限转换路径。由于标准不能要求做某些事情,除非在您的特定情况下无法做到,因此简单的规则是只有一次转换。
考虑一个错综复杂的例子:
template <typename T>
struct A {
operator A<A<T>> () const; // A<int> --> A<A<int>>
};
int x = A<int>();
现在,A<A<A<....A<int>...>>>
可能存在可能转换为int
的特化,因此编译器必须递归实例化A
的无限版本并检查每个版本它们可以转换为int
。
相反,如果有两种类型可转换为任何其他类型,则会导致其他问题:
struct A {
template <typename T>
A(T);
};
struct B {
template <typename T>
operator T() const;
};
struct C {
C(A);
operator B() const;
};
如果允许的多个用户定义的转换,任何类型T可以通过转换路径转换为任何类型U:T - &gt; A - &gt; C - &gt; B - &gt; U.只管理搜索空间对编译器来说是一项艰巨的任务,它很可能会对用户造成混淆。
答案 1 :(得分:2)
恕我直言这是一个基于构造函数默认情况下不明确的事实的设计选择。设置 限制的实际原因是禁止以下表达式有效。
objectn o = 5;
5-> object1(5)->object2(object1)->object3(object2)->...->objectn(objectn-1)
上面的每个箭头都是隐式转换。
一个似乎是一个合理的选择。如果允许更多,您在object0
和objectn
之间有几个隐式转换路径。每一个导致可能不同objectn o.
哪一个选择?
答案 2 :(得分:0)
如果它允许多个,那么序列中有多少个?如果无限,那么对于大型项目中的大量类型来说,它不会变得太复杂吗?例如,每当你添加隐式转换时,你必须非常认真地考虑它转换成什么,然后转换成什么?而且链条还在继续。非常危险的情况,恕我直言。
隐式转换(语言当前允许的内容)被认为是错误的,这就是为什么C ++ 11添加了使用explicit
关键字实现的上下文转换的原因。
答案 3 :(得分:0)
如果允许的数字是无限的,那么你很快就会尝试循环转换序列。
更容易说“如果您需要多次转换,则存在设计缺陷”,并使用该理由在该语言中设置一个保存错误的限制。
在任何情况下,当使用零星时,隐式转换通常被认为是最佳的。一次转换对于标准库使用的重型运算符重载和类似代码非常有用;除此之外,永远使用隐式转换没有太多借口。当然,一种语言会朝着寻求更少而不是更多的方向(例如C ++ 11在此上下文中添加explicit
,以帮助您强制根本没有隐式转换)。