为什么不是common_type <long,unsigned =“”long =“”> :: type = long long?</long,>

时间:2013-03-04 21:27:00

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

common_type<long, unsigned long>::typeunsigned long,因为关于积分推广后的操作数,标准说...

  

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

不要调用整数推广系统错误,但似乎有一个更大的有符号整数类型可以表示它应该使用的有符号和无符号操作数的范围。

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

1 个答案:

答案 0 :(得分:6)

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

  

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

有了这些信息,我们可以在c++ standard,5p10,第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以消除一些意外。

-Hannes