क्या __func__ पॉइंटर्स के दो कॉन्स्ट्रेप इंस्टेंसेस का अंतर अभी भी कॉन्स्टैक्स है?


14

क्या यह वैध सी ++ है?

int main() {
    constexpr auto sz = __func__ - __func__;
    return sz;
}

GCC और MSVC को लगता है कि यह ठीक है, क्लैंग को लगता है कि यह नहीं है: कंपाइलर एक्सप्लोरर


सभी कंपाइलर सहमत हैं कि यह एक ठीक है: कंपाइलर एक्सप्लोरर

int main() {
    constexpr auto p = __func__;
    constexpr auto p2 = p;
    constexpr auto sz = p2 - p;
    return sz;
}

क्लैंग को फिर से यह पसंद नहीं है, लेकिन अन्य इसके साथ ठीक हैं: कंपाइलर एक्सप्लोरर

int main() {
    constexpr auto p = __func__;
    constexpr auto p2 = __func__;
    constexpr auto sz = p2 - p;
    return sz;
}

यहाँ क्या है? मुझे लगता है कि असंबंधित बिंदुओं पर अंकगणित अपरिभाषित व्यवहार है लेकिन __func__उसी सूचक को लौटाता है, नहीं? मुझे यकीन नहीं है, इसलिए मैंने सोचा कि मैं इसका परीक्षण कर सकता हूं। यदि मैं सही ढंग से याद करता हूं, तो std::equal_toअपरिभाषित व्यवहार के बिना असंबंधित बिंदुओं की तुलना कर सकते हैं:

#include <functional>

int main() {
    constexpr std::equal_to<const char*> eq{};
    static_assert(eq(__func__, __func__));
}

क्लैंग सोचता eq(__func__, __func__)है कि एक निरंतर अभिव्यक्ति नहीं है, भले ही std::equal_to::operator() वह अड़चन हो । अन्य संकलक शिकायत नहीं करते हैं: संकलक एक्सप्लोरर


क्लैंग इस एक को भी संकलित नहीं करेगा। शिकायत है कि __func__ == __func__एक निरंतर अभिव्यक्ति नहीं है: कंपाइलर एक्सप्लोरर

int main() {
    static_assert(__func__ == __func__);
}

से Function_definition , __func__के रूप में करता है, तो है static const char __func__[] = "function-name";और उस बराबर स्वीकार किया जाता है डेमो ...
Jarod42

दिलचस्प बात यह है यह काम करता है अगर आप के साथ एक constexpr चर इनिशिएलाइज़ __func__और उपयोग कि static_assert में ...
florestan

@ Jarod42 तो यह क्लेंग में एक बग है?
अयक्सन

इस तरह @florestan ? यह क्लैंग के साथ भी संकलन नहीं करेगा। प्रश्न में मेरे 2 और 3 उदाहरण आपके बताए गए तरीके हैं। एक संकलन करता है, दूसरा नहीं।
अयक्सन

1
CWG1962 भी देखें , जो __func__पूरी तरह से कब्जे के मूल्यांकन से दूर हो सकता है ।
डेविस हेरिंग

जवाबों:


13

__func__C ++ में एक पहचानकर्ता है। विशेष रूप से, यह एक विशिष्ट वस्तु का संदर्भ देता है। से [dcl.fct.def.general] / 8 :

फ़ंक्शन-स्थानीय पूर्वनिर्धारित चर _­_­func_­_­को परिभाषित किया जाता है जैसे कि प्रपत्र की परिभाषा

static const char __func__[] = "function-name";

प्रदान किया गया था, जहां फ़ंक्शन-नाम कार्यान्वयन-परिभाषित स्ट्रिंग है। यह अनिर्दिष्ट है कि क्या इस तरह के एक चर का कार्यक्रम में किसी अन्य ऑब्जेक्ट से अलग पता है।

एक के रूप में समारोह स्थानीय पूर्वनिर्धारित वैरिएबल , इस परिभाषा (जैसे कि) समारोह ब्लॉक की शुरुआत में दिखाई देता है। जैसे, __func__उस खंड के भीतर का कोई भी उपयोग उस चर को संदर्भित करेगा।

"किसी अन्य वस्तु" भाग के लिए, एक चर एक वस्तु को परिभाषित करता है। __func__उस चर द्वारा परिभाषित वस्तु का नाम। इसलिए, एक फ़ंक्शन के भीतर, सभी __func__समान चर नाम का उपयोग करते हैं। क्या अपरिभाषित है कि क्या चर अन्य वस्तुओं से अलग वस्तु है।

यही है, यदि आप नाम वाले एक फ़ंक्शन में हैं foo, और आपने "foo"समस्या में कहीं और शाब्दिक का उपयोग किया है, तो इसे लागू करने के लिए मना नहीं किया जाता है चर __func__भी एक ही वस्तु है कि शाब्दिक "foo"रिटर्न। यही है, मानक के लिए आवश्यक नहीं है कि हर समारोह में__func__ स्ट्रिंग स्ट्रिंग से अलग डेटा संग्रहीत करना आवश्यक है।

अब, C ++ का "मानो" नियम कार्यान्वयन को इससे विचलित करने की अनुमति देता है, लेकिन वे इसे इस तरह से नहीं कर सकते हैं जो पता लगाने योग्य हो। इसलिए, जबकि चर स्वयं अन्य वस्तुओं से एक अलग पता नहीं हो सकता है या नहीं, __func__उसी फ़ंक्शन के उपयोगों को व्यवहार करना चाहिए जैसे कि वे एक ही वस्तु का उल्लेख कर रहे हैं।

क्लैंग लागू नहीं होता है __func__इस तरह । यह इसे लागू करने के लिए प्रतीत होता है जैसे कि यह फ़ंक्शन के नाम का एक प्रचलित स्ट्रिंग शाब्दिक लौटा हो। दो अलग-अलग स्ट्रिंग शाब्दिकों को एक ही ऑब्जेक्ट को संदर्भित करने की आवश्यकता नहीं है, इसलिए उनके लिए पॉइंटर्स को घटाना यूबी है। और एक निरंतर अभिव्यक्ति के संदर्भ में अपरिभाषित व्यवहार बीमार-गठन है।

केवल एक चीज जो मुझे यह कहने में संकोच करती है कि यहाँ क्लैंग 100% गलत है [temp.arg.nontype] [2 :

संदर्भ या पॉइंटर प्रकार के एक गैर-प्रकार के टेम्पलेट-पैरामीटर के लिए, स्थिर अभिव्यक्ति का मूल्य (या एक पॉइंटर प्रकार के लिए, इसका पता नहीं होगा):

...

  • पूर्वनिर्धारित _­_­func_­_चर।

देखिए, इसे लागू करने से कुछ ठगा हुआ लगता है। यही है, जबकि __func__तकनीकी रूप से एक स्थिर अभिव्यक्ति हो सकती है, आप इसे टेम्पलेट पैरामीटर में उपयोग नहीं कर सकते। यह एक स्ट्रिंग शाब्दिक की तरह व्यवहार किया जाता है, भले ही यह तकनीकी रूप से एक चर है।

इसलिए किसी स्तर पर, मैं कहूंगा कि मानक अपने मुंह के दोनों किनारों से बात कर रहा है।


तो, सख्ती से बोलना __func__मेरे सवाल में सभी मामलों में एक निरंतर अभिव्यक्ति हो सकती है, है ना? तो कोड को संकलित करना चाहिए था।
Ayxan

के बारे में क्या "यह अनिर्दिष्ट है कि क्या इस तरह के एक चर कार्यक्रम में किसी भी अन्य वस्तु से अलग एक पता है।" अंश? अनिर्दिष्ट व्यवहार का अर्थ है अमूर्त मशीन के व्यवहार में गैर-निर्धारणवाद। क्या यह विवशता मूल्यांकन के लिए समस्याग्रस्त हो सकती है? क्या होगा यदि __func__पते की पहली घटना किसी अन्य वस्तु के समान है, और दूसरी घटना में __func__नहीं है? दी, इसका मतलब यह नहीं है कि पता दो उदाहरणों के बीच भिन्न है, लेकिन मैं अभी भी भ्रमित हूं!
जोहान्स शाउब -

@ जोहान्सचैब-लिटब: " क्या के बारे में" यह अनिर्दिष्ट है कि क्या इस तरह के एक चर का कार्यक्रम में किसी अन्य वस्तु से अलग पता है। "भाग? " इसके बारे में क्या? __func__स्थूल नहीं है; यह एक पहचानकर्ता है जो एक विशिष्ट चर का नाम देता है और इसलिए एक विशिष्ट वस्तु है। इसलिए, __func__एक ही फ़ंक्शन के किसी भी उपयोग का परिणाम एक चमक में होना चाहिए जो समान ऑब्जेक्ट को संदर्भित करता है। या अधिक बिंदु पर, इसे इस तरह से लागू नहीं किया जा सकता है कि यह मामला नहीं होगा।
निकोल बोलस 20

@ नाइकोल जो उसी वस्तु को संदर्भित करता है। लेकिन उस वस्तु का एक ही पल में किसी अन्य वस्तु के समान पता हो सकता है। और दूसरे पल में नहीं किया है। मैं यह नहीं कह रहा हूं कि यह एक समस्या है, लेकिन मैं सिर्फ इस संभावना की याद दिला रहा हूं। और फिर आखिरकार, मुझसे भी गलती हो सकती है, इसलिए मैं इसे सही होने या पुष्टि होने की उम्मीद में भी कह रहा हूं।
जोहान्स शाउब - २

@ जोहान्सचैब-लिटब: " लेकिन उस वस्तु का एक पल में किसी अन्य वस्तु के समान पता हो सकता है। " यह C ++ ऑब्जेक्ट मॉडल के तहत अनुमति नहीं है। दो वस्तुओं, न तो एक दूसरे के भीतर निहित होने के नाते, दोनों एक ही समय में एक ही भंडारण में अपने जीवनकाल के भीतर नहीं हो सकते। और प्रश्न की वस्तु में स्थिर भंडारण अवधि होती है, इसलिए जब तक आप प्लेसमेंट का उपयोग नहीं करते हैं new, तब तक यह कार्यक्रम समाप्त होने तक कहीं भी नहीं जा सकता है।
निकोल बोलस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.