简而言之,我有以下代码:
float x = cond ? 0 : x_option;
其中x_option
是template<float>
,其中operator float()
(并且没有其他自动转换运算符。请注意此转换后表达式的类型:
bool ? int : float;
我希望这个表达式的结果是float
:
C11:
如果第二个和第三个操作数都有算术类型,那么结果类型就是 通过通常的算术转换确定它们是否应用于这两个操作数, 是结果的类型。
因此它遵循与float + int
相同的规则。
C ++ 11:
第二个和第三个操作数具有算术或枚举类型;通常的算术转换 执行以将它们带到一个共同类型,结果是那种类型。
同样的规则。
但是,clang和cl.exe都会在导致评估第3个参数的路径中生成vcvttss2si
指令,即他们决定bool ? int : float
的结果是int
,而不是float
!
公平地说,C ++ 11有一些规则应该在我引用的规则之前应用,而且说实话,这些规则并不是最容易理解的,尽管从我可以做到的,转换为{{ 1}}不可能:
C ++ 11:
否则,如果第二个和第三个操作数具有不同的类型并且具有(可能是cv限定的)类类型,或者两者都是相同值类别的glvalues和除cv-qualification之外的相同类型,则尝试将每个操作数转换为另一个操作数的类型。确定类型T1的操作数表达式E1是否可以转换为匹配类型T2的操作数表达式E2的过程定义如下:
- 如果E2是左值:如果E1可以被隐式转换(第4条)到类型“左值引用T2”,则E1可以被转换为匹配E2,受限于在转换中引用必须直接绑定(8.5.3)到左值。
- 如果E2是xvalue:如果E1可以隐式转换为“rvalue reference to T2”类型,则E1可以转换为匹配E2,但受到引用必须直接绑定的约束。
- 如果E2是一个右值,或者上面的转换都不能完成,并且至少有一个操作数具有(可能是cv-qualified)类类型:
如果E1和E2具有类类型,并且基础类类型相同或者一个是另一个的基类:如果T2的类与类型相同,则可以将E1转换为匹配E2,或T1的基类,T2的cv资格与T1的cv资格相同的cv资格或更高的cv资格。如果应用转换,则通过从E1复制初始化T2类型的临时值并将该临时值用作转换后的操作数,将E1更改为类型T2的prvalue。
否则(即,如果E1或E2具有非类型类型,或者如果它们都具有类类型但基础类不是相同或一个是另一个的基类):E1可以转换为如果E2可以隐式转换为表达式E2,如果E2被转换为prvalue(或者它具有的类型,如果E2是prvalue),则匹配E2。
使用此过程,确定是否可以转换第二个操作数以匹配第三个操作数,以及是否可以转换第三个操作数以匹配第二个操作数。如果两者都可以转换,或者可以转换,但转换不明确,则程序格式不正确。
根据我在上面的理解,这属于第三种情况的第二种情况(最后一个项目符号点的最后一个要点),因此E1(类型int
)应转换为类型E2(int
)。该标准后来表示如果转换可以双向完成,程序就会形成错误。
这里的裁决是什么?我处于未定义的行为领域吗?或者是标准规定了我所看到的转换?
答案 0 :(得分:10)
bool ? int : float
是一个浮点数。
bool ? int : some_type_convertible_to_float
不是:第三个操作数可以转换为int
(首先转换为float
然后转换为int
); int
(可能)无法转换为some_type_convertible_to_float
。因此,按照您引用的规则,您会获得int
。