当在列表初始化中使用三元运算符时,是什么导致了int
到unsigned int
的隐式转换(对于long long
也是如此),而不是short
到unsigned short
的隐式转化(对于char
也是如此)。
具体来说,我很惊讶i32v2
函数编译得很好,而其他函数则不然:
unsigned short f16(unsigned short x);
unsigned int f32(unsigned int x);
void i16(short value) {
unsigned short encoded{value}; // narrowing, makes sense
}
void i32(int value) {
unsigned int encoded{value}; // narrowing, makes sense
}
void i16v2(short value) {
unsigned short encoded{false ? value : f16(value)}; // narrowing, makes sense
}
void i32v2(int value) {
unsigned int encoded{false ? value : f32(value)}; // not narrowing, huh?
}
完整示例如下:https://godbolt.org/z/fVTcrr
我猜三元运算符隐式地将int
转换为unsigned int
,但我不明白为什么它不能类似地将short
转换为unsigned short
。
我希望,如果int
是可能的,那么三元运算符也应该能够在可能的情况下将任何其他signed
类型转换为unsigned
:
如果目标类型是无符号的,则得到的值是最小的无符号值,等于源值模2n其中n是用于表示目的地类型的比特数。
(https://en.cppreference.com/w/cpp/language/implicit_conversion)
有人能解释这种行为吗?如果可能的话,可以参考标准或适用的cppreference页面吗?
标准说(引用最新草案):
[expr.cond]
对第二个和第三个操作数执行Lvalue到右值、数组到指针以及函数到指针的标准转换。转换后,以下其中一项应成立:
第二个和第三个操作数具有相同的类型[不适用]
第二个和第三个操作数具有算术[applies]或枚举类型执行常见的算术转换,将它们转换为一个通用类型,结果就是该类型。
。。。
[expr.arith.conv]
许多期望算术或枚举类型的操作数的二进制运算符以类似的方式引起转换并产生结果类型。其目的是生成一个公共类型,该类型也是结果的类型。这种模式被称为通常的算术转换,其定义如下:
如果任一操作数是作用域枚举类型[不适用]
如果任一操作数的类型为长双[不适用]
否则,如果任一操作数是双[不适用]
否则,如果任一操作数为浮点[不适用]
否则,应对两个操作数执行积分提升([conv.promm])。则以下规则应适用于提升的操作数:
。。。
[conf.prom]
除bool、char16_t、char32_t或wchar_t[applies]之外的整数类型的prvalue,其整数转换秩([conv.rank])小于int/applies][em>的秩,如果int可以表示源类型[显然应用1][em>所有值,则可以将其转换为int类型的prvalue;否则,源prvalue可以转换为unsigned int类型的prvalue。
这些转换被称为整体促销。
因此,在i16v2
的情况下,第二个和第三个操作数是short
和unsigned short
。显然,1在您的系统上都提升为int
,然后使用条件运算符的int
结果初始化unsigned short
。
在i32v2
的情况下,不适用任何促销,int
和unsigned int
的常见类型为unsigned int
。
1我说显然,因为从技术上讲,在一些大小相同的奇异系统上,unsigned short
可以晋升为unsigned int
,在这种情况下,int
不能代表unsigned short
的所有值。您观察到的结果表明,您的系统并非如此,这是意料之中的事。
注意,对于false ? value : f16(value)
,首先对操作数执行integral_promotion。对于算术运算符,
如果传递给算术运算符的操作数是整型或无范围枚举类型,则在执行任何其他操作之前(但在左值到右值转换之后,如果适用),操作数将进行积分提升。
和
以下隐式转换被归类为积分促销:
signed char
或signed short
可以转换为int
这意味着false ? value : f16(value)
的返回类型是int
,然后导致缩小转换为unsigned short
。
另一方面,返回类型,即false ? value : f32(value)
的常见类型是unsigned int
,则unsigned int encoded{false ? value : f32(value)};
是好的。
否则,操作数具有整数类型(因为
bool
、char
、char8_t
,char16_t
、char32_t
、wchar_t
和无范围枚举在这一点)和积分转换来产生公共类型,如下所示:
- 否则,如果无符号操作数的转换秩大于或等于有符号操作数转换秩转换为无符号操作数的类型
对于long
或long long
,它们不会被提升为int
,那么它们就没有这样的问题。