【问题标题】:Should this be ambiguous or not? (implicit casts)这应该模棱两可吗? (隐式转换)
【发布时间】:2010-11-24 05:30:16
【问题描述】:
 struct A 
 {
     A(const A& src);
     A(const char* src);
 };
 struct B 
 {
     operator A();
     operator char*();
 };
 void test()  
 {
     B v;
     A s(v);
 }

EDG/Comeau 和 MSVC 允许代码,而 GCC 4.4.4、CLANG 和 BCC 拒绝它是模棱两可的。

一位 C++ 委员会成员(最初)这样回答:

这不是模棱两可的; A(const A&) 构造函数比 A(const char*) 构造函数。常量 A& 参数直接绑定到结果 的转换函数,所以 转换序列被认为是 是一个用户定义的转换跟随 通过身份转换 (13.3.3.1.4p1)。常量字符* 参数是用户定义的转换 其次是资格 转换,所以更糟。

然后,他跟进了。

其实我错了。虽然它是 确实,第二次转换 用户定义转换中的序列 序列是决胜局,看起来更多 在 13.3.3.2p3 时, 倒数第二个子弹,表明这 决胜局仅适用于两个 序列包含相同的 用户定义的转换序列,以及 在本例中并非如此。 因为一个构造函数的转换 序列使用 B::operator A() 和 其他用途 b::operator char*(), 两者之间没有决胜局 用户定义的转换序列和 它们是模棱两可的。

我的问题是这个。

13.3.3.2 p3 指出,

两个隐式转换序列 相同的形式是无法区分的 转换序列,除非其中之一 以下规则适用。

据我了解,关键字是“以下规则之一”。 这并不意味着声明“相同转换顺序”的项目符号 覆盖以上所有内容。我会认为“S1的排名更好 比 S2 的等级更适用吗?

【问题讨论】:

  • 很好地证明了 C++ 有点太复杂了......
  • 既然你有一个 c++ 社区成员联系人,你不应该让他提出问题吗? (或检查是否在open-std.org/jtc1/sc22/wg21/docs/cwg_active.html 提交)
  • 我不是说有问题,我实际上是在尝试理解标准。
  • 有趣的是知道 EDG 和 MSVC 允许哪种转换。但这是我不喜欢隐式转换的原因之一,如果我需要转换,我会要求的,谢谢。
  • 显式 = 好,隐式 = 坏

标签: c++ standards casting


【解决方案1】:

是的,根据我对第 13.3.3.2 条的最佳解释,预期结果是歧义

将“B”类型的参数“v”与“A”的任一重载构造函数的参数匹配需要用户定义的转换。这两个序列都是转换等级的。

我的解释是 $13.3.3.2 中的以下引用适用

[...]用户定义的转换顺序 U1 是一个更好的转换序列 比另一个用户定义的转换 序列 U2 如果它们包含相同的 用户定义的转换函数或 构造函数 and 如果是第二个标准 U1的转换顺序更好 比第二个标准转换 U2的序列。

这两种方法都调用了“B”类中的不同转换函数。因此,我认为第一个条件本身不满足,因此预期结果是歧义,因为没有一个转换序列比另一个更好。

【讨论】:

  • 是的,这显然是模棱两可的,因为你提到的确切原因。我不确定为什么这不是公认的答案。它直接指出了为什么以及它是模棱两可的。但是,它具有“转换”等级是错误的。正如您稍后所说,您有两个用户定义的转换序列。对标准转换序列(精确匹配、提升、转换)进行排名。用户定义的转换序列没有排名的概念。
【解决方案2】:

免责声明:这些部分的标准真的很复杂,所以我的理解可能完全错误。

最佳可行函数的标准定义(13.3.3):

鉴于这些定义,一个可行的 函数 F1 被定义为更好 功能比另一个可行的功能 F2 如果对于所有参数 i,ICSi(F1) 是 不比转换序列更差 ICSi(F2),然后

[...]

  • 上下文是用户定义转换的初始化(参见 8.5, 13.3.1.5 和 13.3.1.6) 以及来自 返回类型 F1 到目的地 type(即实体的类型 正在初始化)是一个更好的 转换顺序比标准 从返回的转换序列 类型 F2 到目标类型。

如果我理解正确,正在构造的对象的类型在这里很重要,这将使A::A(const A &) 成为更好的候选者。


请参阅 Johannes cmets 了解为什么此答案不正确:由于 Chubsdad 指出的原因,这确实是模棱两可的。

【讨论】:

  • 绝对相关,+1,但在提到的 2 个上下文中,13.3.1.5 仅涉及非类类型的初始化(如 int),13.3.1.6 仅涉及 references 的初始化。所以我认为它们不适用于这里。
  • @j_random_hacker:是的,但 8.5 确实涵盖了初始化或几乎所有其他内容
  • @icecrime:你是对的,但情节变厚了:根据 8.5/12,A s(v);直接初始化 -- 对吗?然后适用 8.5/14 的第 6 个项目符号。在这里引用太大了,但关键是它没有提到“用户定义的转换”这个词——不像下一个项目符号涵盖(一些)复制初始化案例。所以我不认为你引用的 sn-p 在这里适用,我的结论是 A s(v); 是模棱两可的,但 A s = v; 应该选择 A(const A&) ctor。
  • 我进一步得出结论,C++ 的初始化规则再混乱不过了。
  • 是的,这取决于您的第一个 sn-p 是否适用的解释......事实上它明确提到了 13.3.1.5 和 13.3.1.6 但 13.3.1.3 (这是本案中的相关条款)让我认为不是;但是OTOH显然正在发生用户定义的转换,所以也许确实发生了。根本问题是“通过用户定义的转换进行初始化”实际上并不是 AFAICT 任何地方定义的术语。
猜你喜欢
  • 1970-01-01
  • 2018-01-20
  • 2016-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-10
相关资源
最近更新 更多