2013-03-04 20 views
18

common_type<long, unsigned long>::type è unsigned long perché riguardante gli operandi dopo promozione integrale della norma dice ...Perché non è common_type <long, unsigned long> :: type = long long?

[...] se l'operando che ha firmato tipo intero ha rango maggiore o uguale al rango di tipo dell'altro operando, l'operando con tipo intero con segno deve essere convertito nel tipo di operando con il tipo intero senza segno

non chiamare l'integrale buggy sistema di promozione, ma sembra come se v'è un grande numero intero con segno wh Può rappresentare l'intervallo di operandi sia firmati che non firmati che dovrebbe essere usato.

So che alcune piattaforme potrebbero avere una lunghezza lunga == lungo, nel qual caso la regola di cui sopra può avere effetto. Ma se è un tipo di integrale firmato più grande disponibile, non dovrebbe essere utilizzato?

+4

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

+2

'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. –

+0

@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

risposta

6

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

+0

Allora, qual è la tua domanda? Ho risposto "Perché non è common_type :: type = long long?" Il tuo esempio non aggiunge più informazioni del mio esempio, correggimi se sbaglio. Ma ovviamente 1 <* MaxULong * -1 ... –

+0

Era chiaro nella domanda che lo standard in effetti dice che è così com'è, non avevo bisogno di una risposta che ribadisca che è così * perché lo standard dice così * . Ma come ho detto, sono felice che tu abbia i tuoi link in fondo, sono rilevanti e una risposta parziale (nel senso che è un noto "problema", ma non mostra perché è stato in questo modo per cominciare) – David