c++ language-lawyer integer-promotion

c++ - ¿Por qué common_type no es<long, unsigned long>:: type=long long?



language-lawyer integer-promotion (1)

En primer lugar, std :: common_type (y, por supuesto, boost :: type_traits :: common_type) usa el operador ternario para recuperar el resultado del tipo. En este caso, la cita relevante proviene de la CppReference , 6b)

E2 y E3 tienen un tipo aritmético o de enumeración: las conversiones aritméticas habituales se aplican para llevarlos a un tipo común, ese tipo es el resultado.

Con esta información, podemos encontrar las reglas para las conversiones aritméticas habituales en el estándar de c ++ , 5p10, página 88.

- De lo contrario, si el operando que tiene un tipo entero sin signo tiene un rango mayor o igual al rango del tipo del otro operando, el operando con tipo entero con signo se convertirá al tipo del operando con tipo entero sin signo.

Básicamente, la respuesta a su pregunta es: ... porque la norma así lo dice.

Pero no eres el único que encuentra este comportamiento inesperado. Aquí hay un ejemplo rápido para probar:

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

Pero se known que el comportamiento actual es un problema, y ​​existe una proposal para eliminar algunas de las sorpresas.

-Hannes

common_type<long, unsigned long>::type es unsigned long porque respecto a los operandos después de la promoción integral, el estándar dice ...

[...] si el operando que tiene un tipo entero sin signo tiene un rango mayor o igual al rango del tipo del otro operando, el operando con tipo entero con signo se convertirá al tipo del operando con tipo entero sin signo

No llamar al sistema de promoción integral con errores, pero parece que si hay un tipo entero con signo más grande que pueda representar el rango de los operandos con y sin signo, se debe usar.

Sé que algunas plataformas pueden tener una longitud larga == larga, en cuyo caso la regla anterior puede tener efecto. Pero si hay un tipo integral con signo más grande disponible, ¿no debería usarse?