96 votes

Une déclaration peut-elle affecter l'espace de nom de std ?

<pre><code></code><p><code></code><code></code><code></code><code></code>.</p><p>Je me demande pourquoi cette affaire va se produire?</p><p><code></code></p></pre>

92voto

AndreyT Points 139512

La spécification du langage permet des implémentations à mettre en oeuvre <cmath> en déclarant (et définition) les fonctions standard dans global de l'espace de noms, puis de les amener dans l'espace de noms std par le biais de l'utilisation de déclarations. Il n'est pas précisé si cette approche est utilisée

20.5.1.2 en-Têtes
4 [...] Dans la norme C++ de la bibliothèque, toutefois, les déclarations (sauf pour les noms qui sont définis comme des macros en C) sont dans l'espace de noms de la portée (6.3.6) de l'espace de noms std. Il n'est pas précisé si ces noms (y compris les éventuelles surcharges ajouté dans les alinéas 21 à 33 et à l'Annexe D) sont d'abord déclarés dans l'espace de noms global de la portée et sont ensuite injectés dans l'espace de noms std explicites à l'aide de déclarations (10.3.3).

Apparemment, vous êtes confronté à l'une des implémentations qui a décidé de suivre cette approche (par exemple GCC). I. e. votre mise en œuvre fournit ::abs, tandis que l' std::abs simplement "se réfère à" ::abs.

Une question qui reste dans ce cas est pourquoi, en plus de la norme ::abs vous avez été en mesure de déclarer votre propre ::abs, c'est à dire pourquoi il n'y a pas de définition de plusieurs d'erreur. Cela pourrait être causé par une autre fonctionnalité fournie par certaines implémentations (par exemple GCC): ils déclarent les fonctions standard telles que donc appelé la faiblesse des symboles, vous permettant ainsi de "remplacer" avec vos propres définitions.

Ces deux facteurs ensemble, de créer l'effet que vous observez: faible-symbole de remplacement d' ::abs également des résultats en remplacement de l' std::abs. Comment bien ceci est en accord avec la norme du langage est une autre histoire... En tout cas, ne comptez pas sur ce problème - il n'est pas garanti par la langue.

Dans GCC, ce comportement peut être reproduite par la suite minimaliste exemple. 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 pourrez également observer que la nouvelle définition de l' ::foo ("Goodbye!") dans le deuxième fichier source affecte également le comportement de l' N::foo. Les deux appels de sortie en "Goodbye!". Et si vous supprimez la définition de l' ::foo à partir de la deuxième fichier source, les deux appels envoi de l'original de la" définition de l' ::foo et de sortie "Hello!".


L'autorisation donnée par le ci-dessus 20.5.1.2/4 est là pour simplifier la mise en œuvre de l' <cmath>. Les implémentations sont autorisés à inclure de style C <math.h>, alors redeclare les fonctions en std et ajouter un peu de C++-ajouts et des améliorations. Si l'explication ci-dessus correctement décrit l'intérieur de la mécanique de la question, puis une grande partie de cela dépend de remplacement de la faiblesse des symboles pour le style C versions de ces fonctions.

Notez que si nous avons simplement à l'échelle mondiale remplacer int avec double dans le programme ci-dessus, le code (GCC) va se comporter "comme prévu" - il sera de sortie -5 5. Cela se produit parce que la bibliothèque C standard ne dispose pas d' abs(double) fonction. En déclarant notre propre abs(double), nous n'avons pas de remplacer quoi que ce soit.

Mais si après le passage de l' int avec double nous aussi passer de l' abs de fabs, l'original, le comportement bizarre réapparaît dans toute sa splendeur (sortie -5 -5).

Ceci est cohérent avec l'explication ci-dessus.

13voto

Matt McNabb Points 14273

Votre code provoque un comportement indéterminé.

C++17 [extern.des noms]/4:

Chaque signature de fonction de la bibliothèque C standard déclarée avec une liaison externe est réservé à la mise en œuvre de l'utiliser comme une signature de fonction avec deux extern "C" et extern "C++" lien, ou comme un nom d'espace de noms de champ dans l'espace de noms global.

Si vous ne pouvez pas faire une fonction avec le même prototype que le Standard de la fonction de la bibliothèque C int abs(int);. Indépendamment de qui les en-têtes de vous comprennent, en fait, ou si ceux-têtes aussi mettre de la bibliothèque C noms dans l'espace de noms global.

Cependant, il serait permis de surcharge abs si vous fournir différents types de paramètres.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X