web-dev-qa-db-fra.com

Surcharge ambiguë appel à abs (double)

J'ai le code C++ suivant:

#include <math.h>
#include <cmath.h>      // per http://www.cplusplus.com/reference/clibrary/cmath/abs/

// snip ...

if ( (loan_balance < 0) && (abs(loan_balance) > loan_payment) ) {
    ...
}

et make explose sur:

error: call of overloaded 'abs(double)' is ambiguous

également intéressant:

/usr/include/stdlib.h:785: note: candidates are: int abs(int)

Comment puis-je spécifier que le compilateur doit appeler abs () dans cmath.h qui peut gérer les flottants?

Informations sur le compilateur (je ne sais pas si cela est important):

[some_man@some_box ~/some_code]#  gcc -v
Using built-in specs.
Target: i386-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr    /share/info --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-libgcj-multifile --enable-languages=c,c++,objc,obj-c++,Java,fortran,ada --enable-Java-awt=gtk --disable-dssi --enable-plugin --with-Java-home=/usr/lib/jvm/Java-1.4.2-gcj-1.4.2.0/jre --with-cpu=generic --Host=i386-redhat-linux
Thread model: posix
gcc version 4.1.2 20080704 (Red Hat 4.1.2-44)
56
some_man

L'en-tête <math.h> Est un en-tête C std lib. Il définit beaucoup de choses dans l'espace de noms global. L'en-tête <cmath> Est la version C++ de cet en-tête. Il définit essentiellement les mêmes éléments dans l'espace de noms std. (Il y a quelques différences, comme le fait que la version C++ est livrée avec des surcharges de certaines fonctions, mais cela n'a pas d'importance.) L'en-tête <cmath.h> N'existe pas.

Étant donné que les fournisseurs ne veulent pas conserver deux versions de ce qui est essentiellement le même en-tête, ils ont proposé différentes possibilités de n'en avoir qu'une en arrière-plan. Souvent, c'est l'en-tête C (car un compilateur C++ est capable d'analyser cela, tandis que l'inverse ne fonctionnera pas), et l'en-tête C++ inclut simplement cela et tire tout dans l'espace de noms std. Ou il existe un peu de macro magique pour analyser le même en-tête avec ou sans namespace std Enroulé autour ou non. Ajoutez à cela que dans certains environnements, il est gênant si les en-têtes n'ont pas d'extension de fichier (comme les éditeurs qui ne mettent pas en évidence le code, etc.). Ainsi, certains fournisseurs auraient <cmath> Une ligne unique incluant un autre en-tête avec une extension .h. Ou certains mapperaient toutes les correspondances correspondant à <cblah> À <blah.h> (Qui, grâce à la magie des macros, devient l'en-tête C++ lorsque __cplusplus Est défini et devient autrement l'en-tête C) ou <cblah.h> Ou autre chose.

C'est la raison pour laquelle sur certaines plates-formes, y compris des choses comme <cmath.h>, Qui ne devraient pas exister, réussira initialement, bien que cela puisse faire échouer le compilateur de façon spectaculaire plus tard.

Je n'ai aucune idée de l'implémentation de la librairie std que vous utilisez. Je suppose que c'est celui qui vient avec GCC, mais je ne sais pas, donc je ne peux pas expliquer exactement ce qui s'est passé dans votre cas. Mais c'est certainement un mélange de l'un des hacks spécifiques au vendeur ci-dessus et vous y compris un en-tête que vous n'auriez pas dû vous inclure. C'est peut-être celui où <cmath> Correspond à <cmath.h> Avec un (ensemble de) macro (s) spécifique (s) que vous n'aviez pas défini, de sorte que vous vous retrouvez avec les deux définitions.

Notez cependant que ce code ne doit toujours pas être compilé:

#include <cmath>

double f(double d)
{
  return abs(d);
}

Il ne devrait pas y avoir de abs() dans l'espace de noms global (c'est std::abs()). Cependant, selon les astuces d'implémentation décrites ci-dessus, il pourrait bien y en avoir. Porter ce code plus tard (ou simplement essayer de le compiler avec la prochaine version de votre fournisseur qui ne le permet pas) peut être très fastidieux, vous devez donc garder un œil sur cela.

47
sbi

Cela se résume à ceci: math.h Est de C et a été créé il y a plus de 10 ans. En math.h, en raison de sa nature primitive, la fonction abs() est "essentiellement" juste pour les types entiers et si vous vouliez obtenir la valeur absolue d'un double, vous deviez utiliser fabs(). Lorsque C++ a été créé, il a pris math.h Et l'a fait cmath. cmath est essentiellement math.h mais amélioré pour C++. Il a amélioré des choses comme avoir à faire la distinction entre fabs() et abs, et a simplement créé abs() pour les types doubles et entiers. En résumé: utilisez math.h et utilisez abs() pour les entiers, fabs() pour les doubles ou utilisez cmath et ayez juste des abs pour tout (plus facile et recommandé)

J'espère que cela aide toute personne ayant le même problème!

38
Ruairi Hourihane

Utilisez fabs () au lieu de abs (), c'est la même chose mais pour les flottants au lieu des entiers.

17
Nianliang