为什么common_type<long, unsigned long>::type不等于long long?

20
common_type<long, unsigned long>::typeunsigned long,因为有关整数提升后的操作数,标准规定如下:
如果带有无符号整数类型的操作数的等级大于或等于另一个操作数的类型的等级,则具有有符号整数类型的操作数应转换为具有无符号整数类型的操作数的类型。
并不是说整数提升系统有问题,但如果有更大的有符号整数类型可以表示两个有符号和无符号操作数的范围,那么它应该被使用。
我知道某些平台可能会将long == long long,在这种情况下,上述规则可以生效。但是,如果有更大的有符号整数类型可用,不应该使用它吗?

4
我不相信long long能够完全覆盖unsigned long的整个范围,如果它像其他大小规格说明一样,唯一的要求是用至少与long一样多的位表示。类型提升应该在各个平台上表现出统一性,因此在重载分辨率方面存在一定的可预测性。 - jpm
2
std::common_type 匹配确定三元运算符返回类型的规则。从这个角度来看,三元运算符返回比其两个分支中任何一个更大的类型显然是错误的。 - Lily Ballard
3
你希望(b?(unsigned char)255:(signed char)-1)做什么? - Yakk - Adam Nevraumont
1
@Sh3ljohn 整数提升规则有点奇怪。比 int 小的类型会被提升为 int。我发布的规则是在整数提升之后应用的。 - David
一个相关的问题 std::common_type - Bo Persson
显示剩余6条评论
1个回答

7
首先,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;
}

但当前的行为问题是已知的,而且存在一个建议来减少一些意外情况。
-Hannes

那么你的问题是什么?我回答说:“为什么common_type<long,unsigned long> ::type = long long?”你的例子并没有比我的例子提供更多信息,如果我错了,请纠正我。但当然1 < MaxULong-1... - Hannes M
问题中明确指出标准确实是这样规定的,我不需要一个重申“因为标准如此”而已的答案。但正如我所说,我很高兴你在底部提供了链接,它们是相关的并且是部分答案(因为它是一个已知的“问题”,但并没有说明为什么一开始就是这样)。 - David

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接