Spesifikasi bahasa memungkinkan implementasi untuk diimplementasikan <cmath>dengan mendeklarasikan (dan mendefinisikan) fungsi standar dalam namespace global dan kemudian membawanya ke namespace stddengan menggunakan deklarasi menggunakan. Tidak ditentukan apakah pendekatan ini digunakan
20.5.1.2 Headers
4 [...] Namun, di pustaka standar C ++, deklarasi (kecuali untuk nama yang didefinisikan sebagai makro di C) berada dalam cakupan namespace (6.3.6) dari namespace std. Tidak ditentukan apakah nama-nama ini (termasuk kelebihan beban yang ditambahkan dalam Klausul 21 hingga 33 dan Lampiran D) pertama kali dideklarasikan dalam cakupan namespace global dan kemudian dimasukkan ke dalam namespace stddengan menggunakan deklarasi penggunaan eksplisit (10.3.3).
Rupanya, Anda berurusan dengan salah satu implementasi yang memutuskan untuk mengikuti pendekatan ini (misalnya GCC). Yaitu implementasi Anda menyediakan ::abs, sementara std::abshanya "mengacu" ke ::abs.
Satu pertanyaan yang tersisa dalam kasus ini adalah mengapa selain standar ::absAnda dapat mendeklarasikan milik Anda sendiri ::abs, yaitu mengapa tidak ada kesalahan definisi ganda. Hal ini mungkin disebabkan oleh fitur lain yang disediakan oleh beberapa implementasi (mis. GCC): mereka mendeklarasikan fungsi standar yang disebut simbol lemah , sehingga memungkinkan Anda untuk "menggantinya" dengan definisi Anda sendiri.
Kedua faktor ini bersama-sama menciptakan efek yang Anda amati: penggantian simbol lemah ::absjuga menghasilkan penggantian std::abs. Seberapa baik hal ini sesuai dengan standar bahasa adalah cerita yang berbeda ... Bagaimanapun, jangan mengandalkan perilaku ini - ini tidak dijamin oleh bahasa.
Di GCC, perilaku ini dapat direproduksi dengan contoh minimalis berikut. Satu file sumber
#include <iostream>
void foo() __attribute__((weak));
void foo() { std::cout << "Hello!" << std::endl; }
File sumber lain
#include <iostream>
void foo();
namespace N { using ::foo; }
void foo() { std::cout << "Goodbye!" << std::endl; }
int main()
{
foo();
N::foo();
}
Dalam kasus ini, Anda juga akan mengamati bahwa definisi baru ::foo( "Goodbye!") di file sumber kedua juga memengaruhi perilaku N::foo. Kedua panggilan akan keluar "Goodbye!". Dan jika Anda menghapus definisi dari ::foofile sumber kedua, kedua panggilan akan dikirim ke definisi "asli" ::foodan keluaran "Hello!".
Izin yang diberikan oleh 20.5.1.2/4 di atas ada untuk menyederhanakan implementasi <cmath>. Implementasi diperbolehkan untuk hanya memasukkan C-style <math.h>, kemudian mendeklarasikan kembali fungsi-fungsi tersebut stddan menambahkan beberapa tambahan dan tweak khusus C ++. Jika penjelasan di atas dengan tepat mendeskripsikan mekanisme bagian dalam dari masalah tersebut, maka sebagian besar bergantung pada kemampuan penggantian simbol yang lemah untuk versi C-style dari fungsi tersebut.
Perhatikan bahwa jika kita hanya mengganti secara global intdengan doubledalam program di atas, kode (di bawah GCC) akan berperilaku "seperti yang diharapkan" - itu akan keluar -5 5. Ini terjadi karena pustaka standar C tidak memiliki abs(double)fungsi. Dengan menyatakan milik kita sendiri abs(double), kita tidak mengganti apapun.
Tetapi jika setelah beralih dari intdengan doublekami juga beralih dari abske fabs, perilaku aneh yang asli akan muncul kembali dalam kemuliaan penuh (output -5 -5).
Hal ini sesuai dengan penjelasan di atas.
abssalah.