【问题标题】:Why isn't common_type<long, unsigned long>::type = long long?为什么 common_type<long, unsigned long>::type = long long?
【发布时间】:2013-03-14 05:07:06
【问题描述】:

common_type&lt;long, unsigned long&gt;::typeunsigned long 因为标准说关于积分提升后的操作数...

[...] 如果具有无符号整数类型的操作数的秩大于或 等于另一个操作数的类型的等级,操作数与 有符号整数类型应转换为操作数的类型 无符号整数类型

不要称积分提升系统有问题,但似乎如果有更大的有符号整数类型可以表示有符号和无符号操作数的范围,则应该使用它。

我知道有些平台可能有 long == long long,在这种情况下,上面的规则可以生效。但是如果更大的有符号整数类型可用,不应该使用它吗?

【问题讨论】:

  • 我不相信long long 将涵盖unsigned long 的整个范围。如果它像其他大小规范一样,唯一的要求是它至少用与long 一样多的位表示。无论平台如何,类型提升都应该表现一致,因此对于重载解决方案有一定的可预测性。
  • std::common_type 匹配确定三元运算符返回类型的规则。从这个角度来看,三元运算符返回的类型大于其两个分支中的任何一个似乎显然是错误的。
  • @KevinBallard 我实际上并不认为这显然是错误的。当分支返回不同的签名时返回一个大于其任何一个分支的类型似乎是唯一可以保证没有错误的事情。
  • @KevinBallard 你希望(b?(unsigned char)255:(signed char)-1) 做什么?
  • @Sh3ljohn 积分提升规则是......奇怪。小于int 的类型提升为int。我发布的规则在整体升级后适用。

标签: c++ language-lawyer integer-promotion


【解决方案1】:

首先,std::common_type(当然还有 boost::type_traits::common_type)使用三元运算符来检索类型结果。在这种情况下,相关引用来自CppReference, 6b)

E2 和 E3 具有算术或枚举类型:应用通常的算术转换将它们转换为通用类型,该类型就是结果。

有了这些信息,我们可以在c++ standard, 5p10, page 88 中找到常用算术转换的规则

——否则,如果无符号整数类型的操作数的秩大于或等于另一个操作数类型的秩,则将有符号整数类型的操作数转换为无符号整数类型的操作数的类型.

所以基本上你的问题的答案是:...因为标准是这样说的。

但您并不是唯一一个发现这种行为出乎意料的人。下面是一个可以快速运行的示例:

#include <iostream>
#include <typeinfo>
#include <type_traits>

int main(int argc, const char* argv[])
{

    std::cout << typeid(std::common_type<char, unsigned char>::type).name() << std::endl;
    // I would expect "short", and the result is "int", ok so far.

    std::cout << typeid(std::common_type<short, unsigned short>::type).name() << std::endl;
    // I would expect "int", and the result is "int", yay.

    std::cout << typeid(std::common_type<int, unsigned int>::type).name() << std::endl;
    // I would expect "long", but the result is "unsigned int"

    std::cout << typeid(std::common_type<long, unsigned long>::type).name() << std::endl;
    // I would expect "long long", but the result is "unsigned long"


    // So this usual arithmetic conversion can lead to unexpected behavior:
    auto var_auto = true ? var_i : var_ui;
    std::cout << typeid(var_auto).name() << std::endl;   // unsigned int
    std::cout << var_auto << std::endl;                  // 4294967173

    return 0;
}

但是当前的行为是一个问题是known,而proposal 的存在是为了消除一些意外。

-汉尼斯

【讨论】:

  • 那么你的问题是什么?我回答“为什么不是 common_type::type = long long?”您的示例没有比我的示例添加更多信息,如果我错了,请纠正我。但当然 1 MaxULong-1...
  • 问题中很清楚,标准确实是这样说的,我不需要一个答案来重申它是这样的因为标准是这样说的。但就像我说的,我很高兴你的链接在底部,它们是相关的并且是部分答案(因为这是一个已知的“问题”,但没有说明为什么会这样开始)跨度>
猜你喜欢
  • 2016-07-29
  • 1970-01-01
  • 1970-01-01
  • 2021-05-07
  • 1970-01-01
  • 2016-12-20
  • 2012-01-27
  • 2014-11-03
  • 1970-01-01
相关资源
最近更新 更多