67 votes

Pourquoi mon journal dans l'espace de noms std?

Dans le code ci-dessous, je définir un trivial log fonction. En main j'essaie de ne pas l'appeler, je les appelle std::log. Néanmoins, mon propre log est appelé; et je vois "journal!" à l'écran. Quelqu'un sait-il pourquoi? J'utilise G++ 4.7 et clang++ 3.2.

#include <iostream>
#include <cmath>

double log(const double x) { std::cout << "log!\n"; return x; }

int main(int argc, char *argv[])
{
  std::log(3.14);
  return 0;
}

57voto

aschepler Points 23731

C++ Standard 17.6.1.2 paragraphe 4 (l'emphase est mienne):

Sauf comme il est indiqué dans les paragraphes 18 à 30 et à l'Annexe D, le contenu de chaque en-tête de cname doit être le même que celui de l'en-tête correspondante name.h, comme indiqué dans la bibliothèque Standard C (1.2) ou le C Unicode TR, selon le cas, comme si par inclusion. 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 (3.3.6) de l'espace de noms std. Il n'est pas précisé si ces noms 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 (7.3.3).

g++ est-il la dernière méthode, de sorte que certains des mêmes fichiers d'en-tête peuvent être réutilisés pour le C et le C++. Donc g++ est autorisé à déclarer et définir double log(double) en l'espace de noms global.

Section 17.6.4.3.3 paragraphes 3 et 4:

Chaque nom de la bibliothèque Standard C déclarée avec une liaison externe est réservé à la mise en œuvre de l'utiliser comme un nom avec extern "C" de l'assemblage, à la fois dans l'espace de noms std et dans l'espace de noms global.

Chaque signature de fonction de la bibliothèque Standard C 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++"de l'assemblage, ou comme un nom d'espace de noms de champ dans l'espace de noms global.

Et jusqu'en haut de la Section 17.6.4.3 paragraphe 2:

Si un programme déclare ou définit un nom dans un contexte où il est réservé, autres que celles explicitement autorisées par la présente Clause, son comportement est indéfini.

Vous, en revanche, peuvent ne pas déclarer ou de définir des ::log , en quelque sorte.

Il est dommage que le g++ toolchain ne vous donne pas tous les messages d'erreur, si.

8voto

Puppy Points 90818

Ce qui se passe, je pense, c'est qu' std::log simplement délégués ::log. Malheureusement, ::log seulement fournit un float de surcharge, et vous l'obligeance de nous fournir un double de surcharge, faisant de vous une meilleure adéquation. Mais je ne vois pas comment il obtient même considéré dans la surcharge de jeu.

8voto

DanielKO Points 2151

Sur libstdc++' cmath vous verrez ceci:

using ::log;

Donc, c'est les amener dans les mathématiques.h les fonctions de l'espace de noms global en std. Malheureusement vous fournir une implémentation pour double log(double), alors que l'éditeur de liens ne pas utiliser celui de la lib math. Donc, certainement un bug dans libstdc++.

EDIT: je demande c'est un bug dans libstdc++ std::log ne doivent pas souffrir d'interférences avec la bibliothèque C lorsque vous avez explicitement demandé pour l' std:: versions. Bien sûr, cette façon de remplacer les fonctions de bibliothèque standard est un ancien "fonctionnalité" du langage C.

EDIT 2: j'ai trouvé que le standard n'a pas vraiment interdisent apportant des noms à partir de l'espace de noms global en std. Donc pas un bug, après tout, seulement une conséquence de la mise en œuvre de détails.

6voto

Cornstalks Points 9261

En C++, le compilateur est libre de mettre en œuvre la bibliothèque C dans l'espace de noms global et délégué (cette mise en œuvre est définie).

17.6.1.2.4 Sauf comme indiqué dans les paragraphes 18 à 30 et à l'Annexe D, le contenu de chaque en-tête de cname doit être le même en tant que correspondant du nom d'en-tête.h, comme spécifié dans la bibliothèque standard C (1.2) ou le C Unicode TR, selon le cas, comme si par inclusion. Dans la norme C++ de la bibliothèque, toutefois, les déclarations (sauf pour les les noms qui sont définis comme des macros en C) sont dans l'espace de noms de la portée (3.3.6) de l'espace de noms std. Il est pas spécifié si ces noms sont d'abord déclarés dans l'espace de noms global de la portée et sont ensuite injectées en l'espace de noms std explicites à l'aide de déclarations (7.3.3).

En général, je voudrais éviter de faire une fonction avec la même signature que celui de la bibliothèque C standard. La norme C++ donne certainement des compilateurs de la liberté à l'utilisation de ces signatures s'il le décide, ce qui signifie que vous peut-être les combats de votre compilateur si vous essayez d'utiliser les mêmes signatures. Par conséquent, vous obtenez des résultats bizarres.

Je m'attends à un éditeur de liens d'erreur ou d'avertissement cependant, et je pense qu'il peut être intéressant de signaler cela.

[modifier]

Wow, ninja.

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