2012-05-03 2 views
8

Voglio scrivere un modello che mi restituisce il più piccolo tipo intero con segno che può rappresentare un dato numero. Questa è la mia soluzione:GCC: il confronto è sempre vero a causa della gamma limitata di tipi di dati - in Parametro modello?

/** 
* Helper for IntTypeThatFits. 
* Template parameters indicate whether the given number fits into 8, 16 or 32 
* bits. If neither of them is true, it is assumed that it fits 64 bits. 
*/ 
template <bool fits8, bool fits16, bool fits32> 
struct IntTypeThatFitsHelper { }; 

// specializations for picking the right type 
// these are all valid combinations of the flags 
template<> struct IntTypeThatFitsHelper<true, true, true> { typedef int8_t Result; }; 
template<> struct IntTypeThatFitsHelper<false, true, true> { typedef int16_t Result; }; 
template<> struct IntTypeThatFitsHelper<false, false, true> { typedef int32_t Result; }; 
template<> struct IntTypeThatFitsHelper<false, false, false> { typedef int64_t Result; }; 

/// Finds the smallest integer type that can represent the given number. 
template <int64_t n> 
struct IntTypeThatFits 
{ 
    typedef typename IntTypeThatFitsHelper< 
     (n <= numeric_limits<int8_t>::max()) && (n >= numeric_limits<int8_t>::min()), 
     (n <= numeric_limits<int16_t>::max()) && (n >= numeric_limits<int16_t>::min()), 
     (n <= numeric_limits<int32_t>::max()) && (n >= numeric_limits<int32_t>::min()) 
    >::Result Result; 
}; 

Tuttavia, GCC non accetta questo codice. Ricevo un errore "il confronto è sempre vero a causa della gamma limitata di tipi di dati [-Werror = type-limits]". Perché succede? n è un intero con segno a 64 bit e tutti i confronti possono essere vere o false per diversi valori di n o sto trascurando qualcosa?

Sarò felice per qualsiasi aiuto.

Edit: Devo dire che sto usando C++ 11.

+0

Come potrebbe essere qualcosa _not_ meno di 'max' _e_ non più di' min'? Sto leggendo quello sbagliato? –

+0

@SethCarnegie: Controlla se 'n' rientra negli intervalli per ** diversi ** tipi di dati. –

+0

Per coloro che vogliono cimentarsi in questo, sono riuscito a ottenere una versione su [ideone] (http://ideone.com/PhAJN) (che non supporta 'constexpr' ancora ...) –

risposta

4

E 'un problema con gcc, avvisi in codice basato su modelli può essere frustrante. È possibile modificare l'avviso o utilizzare un altro approccio.

Come forse sapete, il codice basato su modelli viene analizzato due volte:

  • una volta quando primo incontro (parsing)
  • una volta quando un'istanza per un determinato tipo/valore

Il problema qui è che alla istanziazione, il controllo è banale (sì 65 si adatta a un int grazie), e il compilatore non riesce a capire che questo avviso non regge per tutte le istanze :(È davvero molto frustrante per quelli di noi che attaccano Avere un'esperienza di compilazione senza avvisi con gli avvisi su.

avete 3 possibilità:

  • disattivare questo avviso o retrocedere ad un non-errore
  • utilizzare un pragma disattivare selettivamente per questo codice
  • rielaborare il codice in un altro formato così che non attiva più l'avviso

Si noti che a volte la terza possibilità comporta un cambiamento enorme e una soluzione molto più complicata. Io sconsiglio di complicare il codice solo per sbarazzarsi di avvertimenti senza tracce.

EDIT:

Una possibile soluzione:

template <int64_t n> 
struct IntTypeThatFits { 
    static int64_t const max8 = std::numeric_limits<int8_t>::max(); 
    static int64_t const min8 = std::numeric_limits<int8_t>::min(); 

    static int64_t const max16 = std::numeric_limits<int16_t>::max(); 
    static int64_t const min16 = std::numeric_limits<int16_t>::min(); 

    static int64_t const max32 = std::numeric_limits<int32_t>::max(); 
    static int64_t const min32 = std::numeric_limits<int32_t>::min(); 

    typedef typename IntTypeThatFitsHelper< 
     (n <= max8) && (n >= min8), 
     (n <= max16) && (n >= min16), 
     (n <= max32) && (n >= min32) 
    >::Result Result; 
}; 

... cambiando il tipo di dati utilizzati nel confronto, si deve tacere l'avviso del compilatore. Suppongo che il casting esplicito (int64_t(std::numeric_limits<int8_t>::max())) potrebbe funzionare anche, ma ho trovato questo più leggibile.

+0

Quindi questo è un bug in GCC? Dopo tutto, l'avviso ha senso solo per i confronti di runtime. –

+0

@BenjaminSchug: non lo classificherei come * bug * perché potresti obiettare che funziona come previsto. Dopotutto in alcuni casi potresti ** voler ** essere avvisato al momento dell'istanziazione: x È solo che nel tuo caso è dannoso ... –

+0

In questo contesto, il confronto è _qualificato_ essere una costante in fase di compilazione, altrimenti Non potrei usarlo come argomento modello. Quindi se questo è davvero il motivo dell'avvertimento, come mai non è un bug? –

1
typedef typename IntTypeThatFitsHelper< 
     (n <= numeric_limits<int8_t>::max()) && (n >= numeric_limits<int8_t>::min()), 
     (n <= numeric_limits<int16_t>::max()) && (n >= numeric_limits<int16_t>::min()), 
     (n <= numeric_limits<int32_t>::max()) && (n >= numeric_limits<int32_t>::min()) 
    >::Result Result; 

Non si può fare che in C++ (in C++ 11 si può) - numeric_limits<int8_t>::max() non è compilare costante di tempo. Stai usando C++ 11?

BTW, Boost offre questo per voi già: http://www.boost.org/doc/libs/1_49_0/libs/integer/doc/html/boost_integer/integer.html

+0

Sì, I sto usando C++ 11. Avrei dovuto dirlo, mi dispiace. –

+0

Grazie per il suggerimento con Boost, sembra funzionare. Dovrei davvero controllare Boost prima di scrivere qualcosa da solo. :-) –

2

L'errore sta accadendo perché hai chiesto GCC per darvi gli errori di questo avviso con -Werror=type-limits. L'avvertimento -Wtype-limits ti dà un messaggio di avviso se mai fare un confronto che sarà sempre vero a causa degli intervalli di un dato tipo di dati, ad esempio:

uint8_t x; 
if(x >= 0) { ... } // always true, unsigned integers are non-negative 
if(x >= 256) { ... } // always false 

int32_t x; 
if(x < 9223372036854775808LL) { ... } // always true 

Questo avviso può essere a volte utile, ma in molti casi tra cui questa è solo pedanteria inutile e può essere ignorata. E 'normalmente un avvertimento (abilitato come parte di -Wextra, se si utilizza questo), ma con -Werror o -Werror=type-limits, GCC lo rende un errore.

Poiché in questo caso non è effettivamente indicativo di un potenziale problema con il codice, è sufficiente disattivare l'avviso con -Wno-type-limits oppure impostarlo come un errore con Werror=no-type-limits se non si cura di visualizzare quegli avvisi nell'output del compilatore .

+0

Dove nel codice dell'OP c'è un confronto che è sempre vero a causa della gamma di tipi di dati? – interjay

+0

Non voglio disabilitare completamente questo avviso perché è utile nel caso normale.Qui non dovrebbe attivarsi perché il confronto è _supposed_ e _required_ essere una costante di tempo di compilazione. –

0

si ottiene l'avviso perché per alcuni instantations di template <int64_t n> struct IntTypeThatFits con piccole n (più piccolo di 2^32) alcuni tra i confronti sono sempre vero (sic!) A causa della gamma della operando durante la fase di compilazione.

Questo potrebbe essere considerato un avviso falso in questo caso, perché il tuo codice si basa su di esso, OTOH hai chiesto esplicitamente di commetterlo con un -Werror o simile interruttore di linea di comando, in pratica ottieni ciò che hai chiesto qui.

+0

* praticamente ottieni quello che hai chiesto qui * -> Non sono d'accordo. È un avvertimento utile in molte situazioni e ci sono molte istanze del modello in cui non sparerà. Vorrei che i compilatori evitassero tali avvertimenti quando non reggono per ogni istanziazione ... anche se riconosco che è complicato da valutare. –

+0

IMHO generalmente usando '-Werror' sta solo chiedendo dei problemi. Gli avvertimenti sono una buona cosa, ma ci sono molti avvisi fasulli in gcc là fuori per farli erro tutto il tempo. Soprattutto con il codice basato su modelli valutato durante la compilazione. – hirschhornsalz

+0

Non ho problemi con '-Werror' nel mio codice, e questo è come appare il mio elenco di avvisi: http://stackoverflow.com/questions/5088460/flags-to-enable-thorough-and-verbose-g- warnings/9862800 # 9862800 (Di tanto in tanto accendo gli altri avvertimenti che menziono ma dico che non uso). –

1

Penso che le altre risposte di ciò che il problema è sbagliato. Non credo che questo sia un caso di un compilatore eccessivo, ma credo che sia un bug del compilatore. Questo codice spara ancora l'avvertimento:

template<int64_t n> 
bool a() { 
    return (n <= static_cast<int64_t>(std::numeric_limits<int8_t>::max())); 
} 

Quando si chiama a<500>();, ma questo codice non lo fa:

template<int64_t n> 
bool a() { 
    return (n <= static_cast<int64_t>(127)); 
} 

std :: :: numeric_limits max() restituisce 127. Io File un Bugzilla riferire per questo più tardi oggi se nessun altro lo fa.

+0

Si potrebbe considerare un compilatore eccessivamente ansioso compilatore buggy :-) – hirschhornsalz

+0

Ho appena inviato un bug report alla loro mailing list: http://gcc.gnu.org/ml/gcc-bugs/2012-05/msg00311.html –

+1

@BenjaminSchug Meglio usare il bugzilla la prossima volta http : //gcc.gnu.org/bugzilla/. Qualsiasi cosa venga segnalata viene comunque inviata alla mailing list. – hirschhornsalz