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 stdaçı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 ::absiken, std::absbasitçe için "anlamına gelir" ::abs.
Bu durumda geriye kalan bir soru, standarda ek olarak neden ::abskendinizinkini 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 ::absde 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ı ::fooikinci kaynak dosyadan kaldırırsanız , her iki çağrı da "orijinal" tanımına ::foove çı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 stdve 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 intile doublebu çı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 intbirlikte doublebiz de geçiş absiç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.
absyanlış.