Prima di tutto, std :: common_type (e, naturalmente, boost :: type_traits :: common_type) utilizza l'operatore ternario per recuperare il risultato del tipo. In questo caso la citazione pertinente proviene dal CppReference, 6b)
E2 e E3 sono aritmetica o tipo di enumerazione: usuali conversioni aritmetiche vengono applicate a portarli tipo corrente, che tipo è il risultato.
Con queste informazioni siamo in grado di trovare le regole per le usuali conversioni aritmetiche nel c++ standard, 5P10, pagina 88.
- In caso contrario, se l'operando che ha firmato tipo intero ha rango maggiore uguale o uguale al grado del tipo dell'altro operando, l'operando con tipo intero con segno deve essere convertito nel tipo dell'operando con tipo intero senza segno.
Quindi in sostanza la risposta alla tua domanda è: ... perché lo standard dice così.
Ma non sei l'unico a trovare questo comportamento inaspettato. Ecco un esempio eseguibile veloce per provare:
#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;
}
Ma che il comportamento attuale è un problema è known, e un proposal esiste per rimuovere alcune delle sorprese.
-Hannes
Non credo ci sia alcuna garanzia che 'lungo long' comprenderà l'intera gamma di' long' senza segno. Se è come il resto delle specifiche dimensionali, l'unico requisito è che sia rappresentato con almeno tanti bit come 'long'. La promozione del tipo dovrebbe comportarsi uniformemente indipendentemente dalla piattaforma, quindi c'è una certa prevedibilità riguardo alla risoluzione del sovraccarico. – jpm
'std :: common_type' corrisponde alle regole per determinare il tipo di ritorno dell'operatore ternario. Visto in questa luce, sembra ovviamente sbagliato che l'operatore ternario restituisca un tipo più grande di uno dei suoi due rami. –
@KevinBallard In realtà non penso che sembri ovviamente sbagliato.Restituire un tipo più grande di uno dei suoi rami quando i rami restituiscono una firma diversa sembra l'unica cosa da fare che è garantita essere priva di bug. – David