Dil belirtimi , uygulamaların <cmath>
standart işlevleri küresel ad alanında bildirerek (ve tanımlayarak) gerçekleştirmesine ve daha sonra bunları kullanım std
-bildirimleri aracılığıyla ad alanına getirmesine izin verir . Bu yaklaşımın kullanılıp kullanılmadığı belirtilmemiştir.
20.5.1.2 Başlıklar
4 [...] C ++ standart kitaplığında, bildirimler (C'de makro olarak tanımlanan adlar dışında) ad alanının ad alanı kapsamı (6.3.6) içindedir std
. Bu adların (Madde 21'den 33'e ve Ek D'ye eklenen herhangi bir aşırı yük dahil) ilk olarak genel ad alanı kapsamında beyan edilip edilmediği ve daha sonra std
açık kullanım beyanları (10.3.3) ile ad alanına enjekte edilip edilmediği belirtilmemiştir .
Görünüşe göre, bu yaklaşımı izlemeye karar veren uygulamalardan biriyle uğraşıyorsunuz (örn. GCC). Yani sizin uygulama sağlar ::abs
iken, std::abs
basitçe için "anlamına gelir" ::abs
.
Bu durumda geriye kalan bir soru, standarda ek olarak neden ::abs
kendinizinkini de beyan edebildiğiniz ::abs
, yani neden çoklu tanımlama hatası olmadığıdır. Bu, bazı uygulamalar tarafından sağlanan başka bir özellikten kaynaklanıyor olabilir (örneğin, GCC): standart işlevleri zayıf semboller olarak ilan ederler , böylece onları kendi tanımlarınızla "değiştirmenize" izin verirler.
Bu iki faktör birlikte gözlemlediğiniz etkiyi yaratır: Zayıf sembolün yer değiştirmesi ::abs
de yerine geçmesine neden olur std::abs
. Bunun dil standardı ile ne kadar uyumlu olduğu farklı bir hikaye ... Her halükarda, bu davranışa güvenmeyin - dil tarafından garanti edilmez.
GCC'de bu davranış aşağıdaki minimalist örnekle yeniden üretilebilir. Bir kaynak dosya
#include <iostream>
void foo() __attribute__((weak));
void foo() { std::cout << "Hello!" << std::endl; }
Başka bir kaynak dosya
#include <iostream>
void foo();
namespace N { using ::foo; }
void foo() { std::cout << "Goodbye!" << std::endl; }
int main()
{
foo();
N::foo();
}
Bu durumda , ikinci kaynak dosyadaki yeni ::foo
( "Goodbye!"
) tanımının da davranışını etkilediğini gözlemleyeceksiniz N::foo
. Her iki çağrı da çıkacaktır "Goodbye!"
. Ve tanımını ::foo
ikinci kaynak dosyadan kaldırırsanız , her iki çağrı da "orijinal" tanımına ::foo
ve çıktıya gönderilir "Hello!"
.
Yukarıdaki 20.5.1.2/4 tarafından verilen izin, uygulamasını basitleştirmek içindir <cmath>
. Uygulamaların basitçe C stilini içermesine <math.h>
, ardından işlevleri yeniden bildirmesine std
ve C ++ 'ya özgü bazı eklemeler ve ince ayarlar eklemesine izin verilir . Yukarıdaki açıklama, sorunun iç mekaniğini doğru bir şekilde tanımlıyorsa, bunun büyük bir kısmı , işlevlerin C tarzı sürümleri için zayıf sembollerin değiştirilebilirliğine bağlıdır .
Biz sadece global yerine eğer Not int
ile double
bu çıkışı olacak - Yukarıdaki programda, (GCC altında) kodu "beklendiği gibi" davranacaktır -5 5
. Bu, C standart kitaplığının işlevi olmadığı için abs(double)
olur. Kendimizinkini ilan ederek abs(double)
hiçbir şeyin yerini almayız.
Ama geçtikten sonra eğer int
birlikte double
biz de geçiş abs
için fabs
, orijinal garip davranış tüm ihtişamıyla (çıkış yeniden görüntülenecektir -5 -5
).
Bu, yukarıdaki açıklama ile tutarlıdır.
abs
yanlış.