Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why isn't common_type<long, unsigned long>::type = long long?

Tags:

common_type<long, unsigned long>::type is unsigned long because concerning the operands after integral promotion the standard says...

[...] if the operand that has unsigned integer type has rank greater than or equal to the rank of the type of the other operand, the operand with signed integer type shall be converted to the type of the operand with unsigned integer type

Not to call the integral promotion system buggy, but it seems like if there is a bigger signed integer type which can can represent the range of both signed and unsigned operands it should be used.

I know some platforms might have long == long long, in which case the above rule can take effect. But if there is a larger signed integral type available, shouldn't it be used?

like image 783
David Avatar asked Mar 04 '13 21:03

David


People also ask

What is the difference between unsigned long and unsigned long long?

Unsigned long variables are extended size variables for number storage, and store 32 bits (4 bytes). Unlike standard longs unsigned longs won't store negative numbers, making their range from 0 to 4,294,967,295 (2^32 - 1).

How do you define unsigned long long?

An unsigned version of the long long data type. An unsigned long long occupies 8 bytes of memory; it stores an integer from 0 to 2^64-1, which is approximately 1.8×10^19 (18 quintillion, or 18 billion billion). A synonym for the unsigned long long type is uint64 .

What is the difference between unsigned int and unsigned long?

Unsigned int is only guaranteed to be able to hold the numbers between 0 and 65535 (inclusive), while unsigned long int is guaranteed to be able to hold the numbers between 0 and 4 294 967 295. Those are just the minimums, though.

What is an unsigned int?

An unsigned integer is a 32-bit datum that encodes a nonnegative integer in the range [0 to 4294967295]. The signed integer is represented in twos complement notation. The most significant byte is 0 and the least significant is 3.


1 Answers

first of all, std::common_type (and of course boost::type_traits::common_type) use the ternary operator to retrieve the type result. In this case the relevant quote comes from the CppReference, 6b)

E2 and E3 have arithmetic or enumeration type: usual arithmetic conversions are applied to bring them to common type, that type is the result.

With this information we can find the rules for the usual arithmetic conversions in the c++ standard, 5p10, page 88.

— Otherwise, if the operand that has unsigned integer type has rank greater than or equal to the rank of the type of the other operand, the operand with signed integer type shall be converted to the type of the operand with unsigned integer type.

So basically the answer to your question is: ...because the standard says so.

But you are not the only one finding this behavior unexpected. Here's a quick runnable example to try:

#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;
}

But that the current behavior is a problem is known, and a proposal exists to remove some of the surprises.

-Hannes

like image 155
Hannes M Avatar answered Jan 21 '23 16:01

Hannes M