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
long long
will encompass the entire range ofunsigned long
. If it's like the rest of the size specifications, the only requirement is that it is represented with at least as many bits aslong
. Type promotion should behave uniformly regardless of platform, so there is some predictability w/ regard to overload resolution. – jpmstd::common_type
matches the rules for determining the return type of the ternary operator. Viewed in that light, it seems obviously wrong that the ternary operator would return a type larger than either of its two branches. – Lily Ballard(b?(unsigned char)255:(signed char)-1)
to do what? – Yakk - Adam Nevraumontint
promote toint
. The rule I posted applies after intergral promotion. – David