2010-06-29 5 views
5

Je vais avoir un problème dont je suis sûr est simple à corriger, mais je suis à une perte ...de fixation « comparaison est toujours fausse ... » avertissement dans GCC

J'ai un modèle exécute le code suivant:

T value  = d; 
if (std::numeric_limits<T>::is_signed) 
{ 
    if (value < 0) 
    { 
     *this += _T("-"); 
     value = -(signed)value; 
    } 
} 

maintenant, pour des raisons évidentes, GCC me donne un avertissement (comparaison est toujours fausse en raison de gamme limitée de type de données) lorsque ce code est compilé pour un type non signé. Je comprends parfaitement le raisonnement derrière cela et j'ai mis dans la vérification numeric_limits pour voir si je pourrais obtenir le compilateur pour se taire à ce sujet (cela a fonctionné pour MSVC). Hélas sous GCC, je reçois l'avertissement. Y at-il un moyen (à moins de désactiver l'avertissement que je ne sais même pas si vous pouvez faire avec GCC) pour corriger cet avertissement? Le code ne sera jamais appelé de toute façon et je suppose que l'optimiseur le compilera également, mais je ne peux pas me débarrasser de l'avertissement.

Quelqu'un peut-il me donner une solution à cela?

À la votre!

+2

Ceci est TRÈS méchant quand 'int' est 16 bits. Quand 'value' est long,' value = - (signed/* int * /) value' tronque les plus grandes valeurs. Multipliez par '-1' à la place, et laissez l'optimiseur le comprendre. – MSalters

Répondre

5

solution plus simple:

template <typename T> inline bool isNegative(T value) { 
    return std::numeric_limits<T>::is_signed && value < 0; // Doesn't trigger warning. 
} 

T value  = d; 
if (isNegative(value)) // Doesn't trigger warning either. 
{ 
    *this += _T("-"); 
    value = -1 * value; 
} 
+0

Malheureusement, alors que cela corrige l'avertissement sur gcc, il introduit un nouvel avertissement sur MSVC car 'isNegative' n'utilise jamais le paramètre' value' lorsqu'il est appelé avec un type non signé '(avertissement C4100: 'valeur': paramètre formel non référencé)'. Plaire à tous les compilateurs est difficile - il vaut peut-être mieux désactiver l'avertissement que d'écrire du code compilant proprement partout. –

+0

Pour étendre à cela; Je pense que chaque solution que vous trouverez provoquera un avertissement du compilateur ou bien contiendra une logique compliquée qui sera plus difficile à maintenir. –

+0

Je suppose que l'enroulement du 'std :: numeric_limits :: is_signed' dans un modèle de fonction peut supprimer l'avertissement:' template bool is_signed (const T &) {return std :: numeric_limits :: is_signed;} '- Cependant, si il le fait, il (comme la version de MSalters) le fait __ au coût de tourner un contrôle de compilation dans un contrôle d'exécution__. À la fin, je désactiverais probablement l'avertissement dans VC ('#pragma warn (push: 4100)', IIRC) juste avant la ligne incriminée, et je le réactiverais ('#pragma warn (pop)') par la suite. – sbi

3

Quelqu'un peut-il me donner une solution à cela?

Rien de révolutionnaire, mais je le fais habituellement en surchargeant. Quelque chose le long de ces lignes:

//Beware, brain-compiled code ahead! 
template< bool B > 
struct Bool { const static bool result = B; } 

template< typename T > 
void do_it(T& , Bool<false> /*is_signed*/) 
{ 
    // nothing to do for unsigned types 
} 

template< typename T > 
void do_it(T& value, Bool<true> /*is_signed*/) 
{ 
    if (value < 0) { 
     *this += _T("-"); 
     value = -(signed)value; 
    } 
} 

template< typename T > 
void do_something(T& value) 
{ 
    do_it(value, Bool<std::numeric_limits<T>::is_signed>()); 
} 

Si vous pouvez utiliser des modèles de classe au lieu de modèles de fonction, vous pouvez utiliser la spécialisation au lieu de surcharge. (Il n'y a pas de modèle de fonction spécialisation partielle, ce qui rend spécialisée fonction des modèles un peu plus embêtant.)

+0

Un peu trop compliqué - introduire un wrapper de temps de compilation autour de bool et un paramètre supplémentaire pour l'appel? De plus, 'value' doit être passé par une référence non-const, car sa valeur est modifiée. Comme il utilise 'this',' T' est probablement un paramètre template de la classe, pas la fonction. –

+0

Lorsque j'ai commenté, votre solution ne compilerait pas car vous utilisez une référence const pour une valeur mutée. Je suis désolé si vous interprétez cela comme étant «ennuyé» avec vous. Vous pourriez également noter que je n'ai pas voté votre réponse. La modification que j'ai apportée à mon commentaire était d'ajouter la dernière phrase. –

+0

@Joe: Alors je dois avoir mal interprété votre commentaire et je m'excuse pour ma réponse. J'ai enlevé mon commentaire. (Votre commentaire coïncide avec ce qui s'est avéré par la suite être un vote retiré, BTW, que j'ai d'abord pris pour un vote négatif.) Quoi qu'il en soit, concernant le type 'Bool <>': je ne rêverais pas de coder C++ sans ça dans ma boîte à outils. Il est toujours là et j'ai juste besoin de l'attraper quand j'en ai besoin.':)' – sbi

2

Vous pouvez spécialisez votre fonction comme ceci:

template <bool S> 
void manipulate_sign(T&) {} 

template <> 
void manipulate_sign<true>(T& value) { 
    if (value < 0) 
    { 
    *this += _T("-"); 
    value = -(signed)value; 
    } 
} 

//then call like this: 
manipulate_sign<std::numeric_limits<T>::is_signed>(); 

Juste désactiver l'avertissement pourrait être mieux si.

+1

Je certainement envelopper cette fonction afin que l'utilisateur ne doit pas utiliser 'se numeric_limits' -' T' est toutes les informations de la fonction a besoin :) –

3

Voir https://stackoverflow.com/a/8658004/274937 pour la vraie solution, ce qui permet la suppression de -wtype_avertissement limites avertissements au cas par cas. En bref, enroulez chaque comparaison, qui génère l'avertissement, dans une fonction fictive.