【问题标题】:Result of ternary operator on `int` and `float``int` 和 `float` 三元运算符的结果
【发布时间】:2018-08-18 10:32:15
【问题描述】:

简而言之,我有以下代码:

float x = cond ? 0 : x_option;

其中x_optiontemplate<float>,它有一个operator float()(并且没有其他自动转换运算符。请注意此转换后的表达式类型:

bool ? int : float;

我希望这个表达式的结果是float


C11:

如果第二个和第三个操作数都具有算术类型,则结果类型将是 由通常的算术转换确定,它们是否应用于这两个操作数, 是结果的类型。

因此它遵循与例如 float + int 相同的规则。


C++11:

第二个和第三个操作数有算术或枚举类型;通常的算术转换 被执行以将它们带入一个公共类型,并且结果是该类型。

同样的规则。


然而,clang 和 cl.exe 都会在导致评估第三个参数的路径中生成 vcvttss2si 指令,即它们决定 bool ? int : float 的结果是 @987654330 @,不是float

公平地说,C++11 有一些规则应该在我引用的规则之前应用,老实说,这些规则并不是最容易理解的,尽管据我所知,转换为 @987654332 @ 应该是不可能的:

C++11:

否则,如果第二个和第三个操作数具有不同的类型并且具有(可能是 cv 限定的)类类型,或者如果两者都是相同值类别和相同类型(除了 cv 限定)的泛左值,则进行尝试将这些操作数中的每一个转换为另一个的类型。判断一个类型为 T1 的操作数表达式 E1 是否可以转换为匹配一个类型为 T2 的操作数表达式 E2 的过程定义如下:

— 如果 E2 是左值:如果 E1 可以隐式转换(第 4 条)为类型“对 T2 的左值引用”,则可以将 E1 转换为匹配 E2,但必须遵守在转换中引用必须直接绑定的约束(8.5.3) 为左值。

——如果 E2 是一个 xvalue:如果 E1 可以隐式转换为“对 T2 的右值引用”类型,则可以将 E1 转换为匹配 E2,但受引用必须直接绑定的约束。

——如果 E2 是一个右值,或者上面的转换都不能完成,并且至少有一个操作数具有(可能是 cv 限定的)类类型:

  • 如果 E1 和 E2 具有类类型,并且基础类类型相同或其中一个是另一个的基类:如果 T2 的类与以下类型相同,则 E1 可以转换为匹配 E2,或 T1 类的基类,并且 T2 的 cv 限定与 T1 的 cv 限定相同或更高的 cv 限定。如果应用了转换,则通过从 E1 复制初始化 T2 类型的临时值并将该临时值用作转换后的操作数,将 E1 更改为 T2 类型的纯右值。

  • 否则(即,如果 E1 或 E2 具有非类类型,或者如果它们都具有类类型但基础类不同或不是另一个的基类):E1 可以转换为如果 E1 可以隐式转换为表达式 E2 将具有的类型(如果 E2 转换为纯右值)(或它具有的类型,如果 E2 是纯右值),则匹配 E2。

使用这个过程,判断第二个操作数是否可以转换为匹配第三个操作数,以及第三个操作数是否可以转换为匹配第二个操作数。如果两者都可以转换,或者可以转换但转换不明确,则程序格式错误。

根据我上面的理解,这属于第三种情况的第二种情况(最后一个要点的最后一个要点),所以E1(int的类型)应该转换为E2的类型( float)。该标准后来说,如果可以双向进行转换,则该程序是格式错误的。

这里的裁决是什么?我是否处于未定义行为的领域?还是标准决定了我所看到的转换?

【问题讨论】:

  • 虽然从语言律师的角度来看,这是一个有趣的话题,但从软件工程的角度来看,这是相当糟糕的编码实践。让它明确。不要让编译器去猜测你的意图是什么。
  • @RSahu, test ? 0 : value 在我看来是一个非常简单的代码,它不是“让编译器去猜测”。这是我第一次在将0float 混合使用时遇到问题(尽管,因为它不是真正的float,而是一个类似的类),因为0 几乎总是(并且总是在 C 中)被自动视为0.0f(与float 混合时)。
  • 我明白你的意思。不幸的是,在选择某种编码实践时要避免个人偏见并不总是那么容易。

标签: c++ c++11 language-lawyer


【解决方案1】:

bool ? int : float 是一个浮点数。

bool ? int : some_type_convertible_to_float 不是:第三个操作数可以转换为int(先转换为float,然后再转换为int); int(可能)无法转换为some_type_convertible_to_float。所以根据你引用的规则,你会得到一个int

【讨论】:

  • 突然间这很简单!
  • 即使我仍然希望 C++ 尝试将类型简化为算术(在这种情况和类似情况下),然后进行通常的提升...
猜你喜欢
  • 2016-06-26
  • 1970-01-01
  • 1970-01-01
  • 2022-01-11
  • 1970-01-01
  • 2016-07-22
  • 1970-01-01
  • 2012-04-03
  • 1970-01-01
相关资源
最近更新 更多