【发布时间】:2018-08-18 10:32:15
【问题描述】:
简而言之,我有以下代码:
float x = cond ? 0 : x_option;
其中x_option 是template<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在我看来是一个非常简单的代码,它不是“让编译器去猜测”。这是我第一次在将0与float混合使用时遇到问题(尽管,因为它不是真正的float,而是一个类似的类),因为0几乎总是(并且总是在 C 中)被自动视为0.0f(与float混合时)。 -
我明白你的意思。不幸的是,在选择某种编码实践时要避免个人偏见并不总是那么容易。
标签: c++ c++11 language-lawyer