Die Sprachspezifikation ermöglicht die Implementierung von Implementierungen, <cmath>
indem die Standardfunktionen im globalen Namespace deklariert (und definiert) und dann std
mithilfe von using-Deklarationen in den Namespace gebracht werden. Es ist nicht spezifiziert, ob dieser Ansatz verwendet wird
20.5.1.2 Header
4 [...] In der C ++ - Standardbibliothek liegen die Deklarationen (mit Ausnahme von Namen, die in C als Makros definiert sind) jedoch im Namespace-Bereich (6.3.6) des Namespace std
. Es ist nicht spezifiziert, ob diese Namen (einschließlich aller in den Abschnitten 21 bis 33 und Anhang D hinzugefügten Überladungen) zuerst im globalen Namespace-Bereich deklariert und dann std
durch explizite using-Deklarationen (10.3.3) in den Namespace eingefügt werden.
Anscheinend haben Sie es mit einer der Implementierungen zu tun, die sich für diesen Ansatz entschieden haben (z. B. GCC). Dh Ihre Implementierung bietet ::abs
, während std::abs
einfach "bezieht" ::abs
.
Eine Frage, die in diesem Fall noch offen ist, ist, warum Sie zusätzlich zu dem Standard ::abs
Ihren eigenen deklarieren konnten ::abs
, dh warum es keinen Mehrfachdefinitionsfehler gibt. Dies kann durch eine andere Funktion verursacht werden, die von einigen Implementierungen bereitgestellt wird (z. B. GCC): Sie deklarieren Standardfunktionen als sogenannte schwache Symbole , sodass Sie sie durch Ihre eigenen Definitionen "ersetzen" können.
Diese beiden Faktoren zusammen erzeugen den Effekt, den Sie beobachten: Das Ersetzen von schwachen Symbolen führt ::abs
auch zum Ersetzen von std::abs
. Wie gut dies mit dem Sprachstandard übereinstimmt, ist eine andere Geschichte ... Verlassen Sie sich auf keinen Fall auf dieses Verhalten - es wird von der Sprache nicht garantiert.
In GCC kann dieses Verhalten anhand des folgenden minimalistischen Beispiels reproduziert werden. Eine Quelldatei
#include <iostream>
void foo() __attribute__((weak));
void foo() { std::cout << "Hello!" << std::endl; }
Eine andere Quelldatei
#include <iostream>
void foo();
namespace N { using ::foo; }
void foo() { std::cout << "Goodbye!" << std::endl; }
int main()
{
foo();
N::foo();
}
In diesem Fall werden Sie auch feststellen, dass die neue Definition von ::foo
( "Goodbye!"
) in der zweiten Quelldatei auch das Verhalten von beeinflusst N::foo
. Beide Anrufe werden ausgegeben "Goodbye!"
. Wenn Sie die Definition von ::foo
aus der zweiten Quelldatei entfernen , werden beide Aufrufe an die "ursprüngliche" Definition von ::foo
ausgegeben und ausgegeben "Hello!"
.
Die Erlaubnis des obigen 20.5.1.2/4 dient dazu, die Implementierung von zu vereinfachen <cmath>
. Implementierungen dürfen einfach C-Stil enthalten <math.h>
, dann die Funktionen neu deklarieren std
und einige C ++ - spezifische Ergänzungen und Optimierungen hinzufügen. Wenn die obige Erklärung die innere Mechanik des Problems richtig beschreibt, hängt ein Großteil davon von der Ersetzbarkeit schwacher Symbole für C-Versionen der Funktionen ab.
Beachten Sie, dass , wenn wir einfach global ersetzen int
mit double
in dem obigen Programm wird der Code (unter GCC) „wie erwartet“ verhalten - es wird ausgegeben -5 5
. Dies geschieht, weil die C-Standardbibliothek keine abs(double)
Funktion hat. Indem abs(double)
wir unsere eigenen deklarieren , ersetzen wir nichts.
Wenn wir aber nach dem Wechsel von int
mit double
auch von abs
zu wechseln , fabs
wird das ursprüngliche seltsame Verhalten in seiner vollen Pracht (Ausgabe -5 -5
) wieder auftauchen .
Dies steht im Einklang mit der obigen Erklärung.
abs
ist falsch.