7 c++ conversion-operator implicit-conversion
我只是想澄清C++是如何工作的,这不是关于解决我的代码中的特定问题.
在C++中,您可以说类型A应该以两种不同的方式隐式转换为类型B.
如果您是A的作者,可以在A中添加这样的内容:
operator B() {
// code
}
Run Code Online (Sandbox Code Playgroud)
如果您是B的作者,可以向B添加这样的内容:
B(const A &a) {
// code
}
Run Code Online (Sandbox Code Playgroud)
如果我理解正确,其中任何一个都将允许A隐式转换为B.所以,如果两个都被定义使用哪一个?这甚至是允许的吗?
注意:我知道您可能永远不会遇到这种情况.您可以使构造函数显式,也可以只使用两者中的一个.我只是想知道C++规范说的是什么,我不知道如何看待它.
不幸的是,这个问题的答案可能比您想要的更复杂。正如 Orbit 中的 Lightness Races 指出的那样,编译器确实会拒绝不明确的转换,但是这些转换是否不明确?让我们看几个案例。所有引用均参考 C++11 标准。
\n\n这并不能直接解决您的问题,因为您询问了隐式转换,但由于轨道中的 Lightness Races 给出了显式转换的示例,因此我无论如何都会讨论它。
\n\n显式转换执行时间A为B:
(B)a,其中a的类型为A,在本例中相当于static_cast<B>(a)(C++11 标准,\xc2\xa75.4/4)。B t(a);您使用静态强制转换,在本例中将创建一个临时变量,该临时变量的初始化方式与声明初始化的方式相同t;(\xc2\xa75.2.9/4)B(a),它相当于(B)a并因此也与声明中的初始化B t(a);(\xc2\xa75.2.3/1)执行相同的操作B因此,在每种情况下,都会使用类型的值A作为参数对类型的纯右值执行直接初始化。\xc2\xa78.5/16 指定仅考虑构造函数,因此B::B(const A&)将被调用。(有关更多详细信息,请参阅我的答案:/sf/answers/1571148211/)
在复制初始化中
\n\nB b = a;\nRun Code Online (Sandbox Code Playgroud)\n\natype 的值首先使用用户定义的转换序列A转换为临时的 type ,这是一个隐式转换序列。B然后这个临时用于直接初始化b。
因为这是由不同类类型的对象对类类型进行复制初始化,所以转换构造函数B::B(const A&)和转换函数A::operator B()都是转换的候选者 (\xc2\xa713.3.1.4)。调用后者是因为它赢得了重载决策。请注意,如果B::B有参数A&而不是const A&,则重载将不明确,并且程序将无法编译。有关标准的详细信息和参考,请参阅此答案:https ://stackoverflow.com/a/1384044/481267
复制列表初始化
\n\nB b = {a};\nRun Code Online (Sandbox Code Playgroud)\n\n只考虑B(\xc2\xa78.5.4/3) 的构造函数,而不考虑 的转换函数A,因此B::B(const A&)将被调用,就像显式转换一样。
如果我们有
\n\nvoid f(B b);\nA a;\nf(a);\nRun Code Online (Sandbox Code Playgroud)\n\n那么编译器必须选择最佳的隐式转换序列来转换a为类型B,以便将其传递给f. 为此,考虑用户定义的转换序列,其中包含一个标准转换,后跟一个用户定义的转换,再后跟另一个标准转换 (\xc2\xa713.3.3.1.2/1)。用户定义的转换可以通过转换构造函数B::B(const A&)或转换函数进行A::operator B()。
这就是事情变得棘手的地方。标准中有一些令人困惑的措辞:
\n\n\n\n\n由于隐式转换序列是初始化,因此在为用户定义转换序列选择最佳用户定义转换时,将应用用户定义转换的初始化特殊规则(请参阅 13.3.3 和 13.3.3.1)。
\n
(\xc2\xa713.3.3.1.2/2)
\n\n长话短说,这意味着用户定义转换序列中从A到 的用户定义转换B本身受到重载解析的影响;A::operator B()胜出是B::B(const A&)因为前者的简历资格较少(如在复制初始化的情况下),如果我们有而B::B(A&)不是 ,则会导致歧义B::B(const A&)。请注意,这不会导致重载解析的无限递归,因为不允许用户定义的转换将参数转换为用户定义的转换的参数类型。
在
\n\nB foo() {\n return A();\n}\nRun Code Online (Sandbox Code Playgroud)\n\n表达式A()隐式转换为类型B(\xc2\xa76.6.3/2),因此应用与函数参数隐式转换相同的规则;A::operator B()将被调用,如果我们有 ,那么重载将是不明确的B::B(A&)。然而,如果换做是
return {A()};\nRun Code Online (Sandbox Code Playgroud)\n\n那么这将是一个复制列表初始化(再次是\xc2\xa76.6.3/2);B::B(const A&)将被调用。
注意:处理异常时不会尝试用户定义的转换;块catch(B)无法处理throw A();.
| 归档时间: |
|
| 查看次数: |
126 次 |
| 最近记录: |