19

我有以下代码:

uint16_t getLastMarker(const std::string &number);
...
const auto msgMarker = getLastMarker(msg.number) + static_cast<uint16_t>(1);
static_assert(std::is_same<decltype(msgMarker), const int>::value, "Should fail");
static_assert(std::is_same<decltype(msgMarker), const uint16_t>::value, "Should not fail");

我希望第一个断言会失败,而第二个断言不会。然而gcc 4.9.2clang 3.6反其道而行之。如果我在代码中使用 uint16_t 而不是 auto ,则正确的断言会失败,而另一个断言会成功。

PS 最初我只是1代替static_cast<uint16_t>(1)并认为问题是由于数字文字1的类型为 int 但即使在此处显式转换后错误断言也会失败。

4

2 回答 2

16

加法将对其操作数执行通常的算术转换,在这种情况下,由于整数提升,操作数将被提升为int,结果也将是int

您可以使用uint16_t而不是 auto 强制转换回来,或者在一般情况下您可以使用static_cast.

有关为什么将小于int的类型提升为更大类型的基本原理,请参阅为什么在 C 和 C++ 中的算术运算之前必须将 short 转换为 int?.

作为参考,来自草案 C++ 标准部分5.7 Additive operator

[...]对算术或枚举类型的操作数执行通常的算术转换[...]

并从5 表达式部分:

[...]否则,应在两个操作数上执行积分提升 (4.5)。59那么以下规则应适用于提升的操作数[...]

并从4.5 整体促销部分(重点是我的):

如果 int 可以表示源类型的所有值,则可以将除 bool、char16_t、char32_t 或 wchar_t的整数转换等级 (4.13) 小于 int 等级的整数类型的纯右值转换为 int 类型的纯右值; 否则,可以将源纯右值转换为 unsigned int 类型的纯右值。

假设int大于 16 位。

于 2015-05-12T13:18:18.247 回答
8

算术运算不适用于任何小于int. 因此,如果uint16_t小于int,它将在执行加法之前被提升为int(或者可能是更大的类型,如果需要匹配另一个操作数)。

添加的结果将是提升的类型。如果您想要其他类型,则必须在之后进行转换。

于 2015-05-12T13:22:17.880 回答