भाषा विनिर्देश वैश्विक नामस्थान में मानक कार्यों को घोषित (और परिभाषित) करके कार्यान्वयन के लिए कार्यान्वयन की अनुमति देता है और फिर उपयोग-घोषणाओं के माध्यम से उन्हें नामस्थान में लाया जाता है। यह अनिर्दिष्ट है कि क्या इस दृष्टिकोण का उपयोग किया जाता है<cmath>
std
20.5.1.2 हेडर्स
4 [...] सी ++ मानक पुस्तकालय में, हालांकि, घोषणाएं (सी में मैक्रोज़ के रूप में परिभाषित किए गए नामों को छोड़कर) नाम स्थान के नाम स्थान (6.3.6) के भीतर हैं std
। यह अनिर्दिष्ट है कि क्या ये नाम (क्लॉज़ 21 में 33 और एनेक्स डी के माध्यम से जोड़े गए किसी भी अधिभार सहित) को पहले वैश्विक नाम स्थान के दायरे में घोषित किया गया है और फिर std
स्पष्ट उपयोग-घोषणाओं (10.3.3) द्वारा नामस्थान में अंतःक्षिप्त किया गया है।
जाहिरा तौर पर, आप इस दृष्टिकोण (जैसे जीसीसी) का पालन करने का फैसला करने वाले कार्यान्वयन में से एक के साथ काम कर रहे हैं। यानी आपका कार्यान्वयन प्रदान करता है ::abs
, जबकि std::abs
बस "संदर्भित" करता है ::abs
।
इस मामले में एक सवाल यह है कि मानक के अलावा ::abs
आप अपनी खुद की घोषणा करने में सक्षम ::abs
क्यों थे, अर्थात कोई एकाधिक परिभाषा त्रुटि क्यों नहीं है। यह कुछ कार्यान्वयनों (जैसे जीसीसी) द्वारा प्रदान की गई एक अन्य विशेषता के कारण हो सकता है: वे मानक कार्यों को तथाकथित कमजोर प्रतीकों के रूप में घोषित करते हैं , इस प्रकार आप उन्हें अपनी परिभाषाओं के साथ "प्रतिस्थापित" करने की अनुमति देते हैं।
ये दो कारक मिलकर आपके द्वारा बनाए गए प्रभाव का निर्माण करते हैं: कमजोर-प्रतीक प्रतिस्थापन के ::abs
परिणामस्वरूप भी प्रतिस्थापन होता है std::abs
। भाषा मानक के साथ यह कितनी अच्छी तरह से सहमत है एक अलग कहानी है ... किसी भी मामले में, इस व्यवहार पर भरोसा न करें - यह भाषा की गारंटी नहीं है।
जीसीसी में इस व्यवहार को निम्नलिखित न्यूनतर उदाहरण द्वारा पुन: प्रस्तुत किया जा सकता है। एक स्रोत फ़ाइल
#include <iostream>
void foo() __attribute__((weak));
void foo() { std::cout << "Hello!" << std::endl; }
एक अन्य स्रोत फ़ाइल
#include <iostream>
void foo();
namespace N { using ::foo; }
void foo() { std::cout << "Goodbye!" << std::endl; }
int main()
{
foo();
N::foo();
}
इस मामले में आप यह भी देखेंगे कि दूसरी स्रोत फ़ाइल में ::foo
( "Goodbye!"
) की नई परिभाषा के व्यवहार को भी प्रभावित करता है N::foo
। दोनों कॉल आउटपुट करेंगे "Goodbye!"
। और यदि आप ::foo
दूसरी स्रोत फ़ाइल से परिभाषा को हटाते हैं , तो दोनों कॉल "मूल" ::foo
और आउटपुट की परिभाषा को भेज देंगे "Hello!"
।
उपरोक्त 20.5.1.2/4 द्वारा दी गई अनुमति के कार्यान्वयन को सरल बनाने के लिए है <cmath>
। कार्यान्वयन को केवल सी-शैली में शामिल करने की अनुमति है <math.h>
, फिर कार्यों को फिर से std
जोड़ने और कुछ सी ++ - विशिष्ट परिवर्धन और ट्वीक्स जोड़ें। यदि उपरोक्त स्पष्टीकरण मुद्दे के आंतरिक यांत्रिकी का ठीक से वर्णन करता है, तो इसका एक प्रमुख हिस्सा कार्यों के सी-शैली संस्करणों के लिए कमजोर प्रतीकों की पुनरावृत्ति पर निर्भर करता है।
ध्यान दें कि यदि हम उपरोक्त कार्यक्रम में केवल विश्व स्तर पर प्रतिस्थापित int
करते हैं double
, तो कोड (GCC के तहत) "अपेक्षित रूप से व्यवहार करेगा" - यह आउटपुट होगा -5 5
। ऐसा इसलिए होता है क्योंकि C मानक लाइब्रेरी में abs(double)
फ़ंक्शन नहीं होता है। अपनी खुद की घोषणा करके abs(double)
, हम कुछ भी प्रतिस्थापित नहीं करते हैं।
लेकिन अगर से स्विच करने के बाद int
साथ double
हम भी से स्विच abs
करने के लिए fabs
, मूल अजीब व्यवहार अपनी पूरी महिमा (उत्पादन में फिर से दिखाई देगा -5 -5
)।
यह उपरोक्त स्पष्टीकरण के अनुरूप है।
abs
गलत है।