La spécification du langage permet aux implémentations d'implémenter <cmath>en déclarant (et en définissant) les fonctions standard dans l' espace de noms global , puis en les amenant dans l'espace stdde noms au moyen de déclarations d'utilisation. Il n'est pas précisé si cette approche est utilisée
20.5.1.2 En-têtes
4 [...] Dans la bibliothèque standard C ++, cependant, les déclarations (à l'exception des noms qui sont définis comme des macros en C) sont dans la portée de l'espace de noms (6.3.6) de l'espace de noms std. Il n'est pas précisé si ces noms (y compris les surcharges ajoutées dans les Articles 21 à 33 et dans l'Annexe D) sont d'abord déclarés dans la portée de l'espace de noms global et sont ensuite injectés dans l'espace stdde noms par des déclarations d'utilisation explicites (10.3.3).
Apparemment, vous avez affaire à l'une des implémentations qui a décidé de suivre cette approche (par exemple GCC). Ie votre mise en œuvre fournit ::abs, tout std::abssimplement "se réfère" à ::abs.
Une question qui demeure dans ce cas est de savoir pourquoi en plus du standard ::absvous avez pu déclarer le vôtre ::abs, c'est-à-dire pourquoi il n'y a pas d'erreur de définition multiple. Cela peut être causé par une autre fonctionnalité fournie par certaines implémentations (par exemple GCC): elles déclarent des fonctions standard comme des symboles dits faibles , vous permettant ainsi de les "remplacer" par vos propres définitions.
Ensemble, ces deux facteurs créent l'effet que vous observez: le remplacement d'un symbole faible de ::absentraîne également le remplacement de std::abs. À quel point cela s'accorde avec la norme de la langue est une autre histoire ... Dans tous les cas, ne vous fiez pas à ce comportement - il n'est pas garanti par la langue.
Dans GCC, ce comportement peut être reproduit par l'exemple minimaliste suivant. Un fichier source
#include <iostream>
void foo() __attribute__((weak));
void foo() { std::cout << "Hello!" << std::endl; }
Un autre fichier source
#include <iostream>
void foo();
namespace N { using ::foo; }
void foo() { std::cout << "Goodbye!" << std::endl; }
int main()
{
foo();
N::foo();
}
Dans ce cas, vous observerez également que la nouvelle définition de ::foo( "Goodbye!") dans le deuxième fichier source affecte également le comportement de N::foo. Les deux appels seront émis "Goodbye!". Et si vous supprimez la définition de ::foodu deuxième fichier source, les deux appels seront envoyés à la définition «d'origine» ::fooet à la sortie "Hello!".
L'autorisation donnée par le 20.5.1.2/4 ci-dessus est là pour simplifier la mise en œuvre de <cmath>. Les implémentations sont autorisées à simplement inclure le style C <math.h>, puis à redéclarer les fonctions stdet à ajouter des ajouts et des modifications spécifiques à C ++. Si l'explication ci-dessus décrit correctement la mécanique interne du problème, alors une grande partie de celui-ci dépend de la remplaçabilité des symboles faibles pour les versions de style C des fonctions.
Notez que si nous remplaçons simplement globalement intpar doubledans le programme ci-dessus, le code (sous GCC) se comportera "comme prévu" - il sortira -5 5. Cela se produit parce que la bibliothèque standard C n'a pas de abs(double)fonction. En déclarant le nôtre abs(double), nous ne remplaçons rien.
Mais si, après le passage de intavec, doublenous passons également de absà fabs, le comportement étrange d'origine réapparaîtra dans toute sa splendeur (sortie -5 -5).
Ceci est cohérent avec l'explication ci-dessus.
absest incorrecte.