La specifica del linguaggio consente l' implementazione delle implementazioni <cmath>dichiarando (e definendo) le funzioni standard nello spazio dei nomi globale e quindi portandole nello spazio stddei nomi mediante dichiarazioni-utilizzo. Non è specificato se questo approccio viene utilizzato
20.5.1.2 Intestazioni
4 [...] Nella libreria standard C ++, tuttavia, le dichiarazioni (ad eccezione dei nomi che sono definiti come macro in C) rientrano nell'ambito dello spazio dei nomi (6.3.6) dello spazio dei nomi std. Non è specificato se questi nomi (inclusi eventuali sovraccarichi aggiunti nelle clausole da 21 a 33 e nell'Allegato D) siano prima dichiarati all'interno dell'ambito dello spazio dei nomi globale e siano poi iniettati nello spazio stddei nomi da dichiarazioni using esplicite (10.3.3).
Apparentemente, hai a che fare con una delle implementazioni che hanno deciso di seguire questo approccio (ad es. GCC). Cioè la tua implementazione fornisce ::abs, mentre std::abssemplicemente "si riferisce" a ::abs.
Una domanda che rimane in questo caso è perché oltre allo standard ::abssei stato in grado di dichiarare il tuo ::abs, cioè perché non c'è errore di definizione multipla. Ciò potrebbe essere causato da un'altra caratteristica fornita da alcune implementazioni (es. GCC): dichiarano le funzioni standard come i cosiddetti simboli deboli , consentendo così di "sostituirle" con le proprie definizioni.
Questi due fattori insieme creano l'effetto che osservi: la sostituzione del simbolo debole di ::abscomporta anche la sostituzione di std::abs. Quanto questo concordi con lo standard linguistico è un'altra storia ... In ogni caso, non fare affidamento su questo comportamento - non è garantito dalla lingua.
In GCC questo comportamento può essere riprodotto dal seguente esempio minimalista. Un file sorgente
#include <iostream>
void foo() __attribute__((weak));
void foo() { std::cout << "Hello!" << std::endl; }
Un altro file sorgente
#include <iostream>
void foo();
namespace N { using ::foo; }
void foo() { std::cout << "Goodbye!" << std::endl; }
int main()
{
foo();
N::foo();
}
In questo caso osserverai anche che la nuova definizione di ::foo( "Goodbye!") nel secondo file sorgente influenza anche il comportamento di N::foo. Entrambe le chiamate verranno emesse "Goodbye!". E se rimuovi la definizione di ::foodal secondo file sorgente, entrambe le chiamate verranno inviate alla definizione "originale" ::fooe all'output "Hello!".
L'autorizzazione data dal precedente 20.5.1.2/4 serve a semplificare l'implementazione di <cmath>. Le implementazioni possono includere semplicemente lo stile C <math.h>, quindi dichiarare nuovamente le funzioni stde aggiungere alcune aggiunte e modifiche specifiche per C ++. Se la spiegazione di cui sopra descrive adeguatamente i meccanismi interni del problema, una parte importante di essa dipende dalla sostituibilità dei simboli deboli per le versioni in stile C delle funzioni.
Nota che se sostituiamo globalmente intcon doublenel programma precedente, il codice (sotto GCC) si comporterà "come previsto" - verrà visualizzato -5 5. Ciò accade perché la libreria standard C non ha abs(double)funzioni. Dichiarando il nostro abs(double), non sostituiamo nulla.
Ma se dopo il passaggio da intcon doublesi passa anche da absa fabs, il comportamento strano originale riapparirà nella sua piena gloria (output -5 -5).
Ciò è coerente con la spiegazione di cui sopra.
absnon è corretta.