अगर लैम्ब्डा में static_assert के साथ कॉन्स्टैक्स होता है, तो कौन सा कंपाइलर सही है?


13

जब हम एक static_assertमें उपयोग करना चाहते हैं तो हमें if constexprकुछ टेम्पलेट पैरामीटर पर निर्भर होना चाहिए। दिलचस्प बात यह है कि जब कोड लैम्बडा में लपेटा जाता है तो जीसीसी और क्लैग असहमत होते हैं।

निम्न कोड gcc के साथ संकलित करता है, लेकिन क्लैग मुखर को ट्रिगर करता है, भले ही वह if constexprसच न हो।

#include <utility>

template<typename T> constexpr std::false_type False;

template<typename T>
void foo() {

    auto f = [](auto x) {
        constexpr int val = decltype(x)::value;
        if constexpr(val < 0) {
            static_assert(False<T>, "AAA");
        }
    };

    f(std::integral_constant<int, 1>{});
}

int main() {
    foo<int>();
}

इसका जीता जागता उदाहरण है

इसे आसानी से प्रतिस्थापित False<T>करके तय किया जा सकता है False<decltype(x)>

तो सवाल यह है कि कौन सा संकलक सही है? मुझे लगता है कि जीसीसी सही है क्योंकि हालत static_assertपर निर्भर है T, लेकिन मुझे यकीन नहीं है।


यह एक ही तरह का प्रश्न पूछता है लेकिन विपरीत दिशा से आ रहा है: stackoverflow.com/questions/59393908/…
नाथनऑलिवर

1
@ एमएफएनएक्स पुन: पेश नहीं कर सकता । क्या आप एक उदाहरण साझा कर सकते हैं?
नाथनऑलिवर

2
मैं कहूंगा कि दोनों सही हैं (बीमार एनडीआर): लंबोदर static_assert(False<int>, "AAA");के static_assert(false, "AAA");अंदर बराबर है ।
Jarod42

2
@mfnx आपने स्थिरांक का मान बदल दिया है। ओपी के उदाहरण का उपयोग करना जहां निरंतर f(std::integral_constant<int, 1>{});Wandbox मुखर ट्रिगर नहीं करता है: wandbox.org/permlink/UFYAmYwtt1ptsndr
NathanOliver

1
@NathanOliver हाँ आप सही हैं, शोर के लिए क्षमा करें। ऐसा लगता है कि कॉन्स्टैक्स में कोड ठीक उसी तरह से खारिज किया जाना चाहिए जब स्थिर> = 0;
mfnx

जवाबों:


1

से [stmt.if] / 2 (जोर मेरा)

यदि अगर बयान फॉर्म का है अगर कॉन्स्टैक्स, स्थिति का मूल्य प्रकार के बूल का एक प्रासंगिक रूप से परिवर्तित स्थिर अभिव्यक्ति होगा; इस फॉर्म को स्टेटमेंट कहा जाता है। यदि परिवर्तित स्थिति का मान गलत है, तो पहला सबस्टेशन एक डिस्क्राइब्ड स्टेटमेंट है, अन्यथा दूसरा सबस्टेशन, यदि मौजूद है, तो एक खारिज किया गया स्टेटमेंट है। एक संलग्न टेम्प्लेटेड इकाई ([temp.pre]) की तात्कालिकता के दौरान, यदि स्थिति उसके तात्कालिकता के बाद मूल्य-निर्भर नहीं है, तो खारिज किए गए सबस्टेशन (यदि कोई हो) को तत्काल नहीं किया जाता है।

यह पढ़कर कि किसी को लगता है कि स्थिर मुखर को हटा दिया जाएगा, लेकिन ऐसा नहीं है।

स्थिर मुखर टेम्पलेट के पहले चरण में चालू हो जाता है क्योंकि संकलक जानता है कि यह हमेशा गलत है।

से [temp.res] / 8 (जोर मेरा)

किसी भी तात्कालिकता से पहले एक टेम्पलेट की वैधता की जाँच की जा सकती है। [ नोट: यह जानना कि कौन से नाम टाइप नाम हैं, इस तरह से हर टेम्प्लेट के सिंटैक्स की जाँच की जा सकती है। - अंत नोट ] कार्यक्रम बीमार है, कोई नैदानिक ​​की आवश्यकता नहीं है, अगर:

  • ((.१) किसी टेम्पलेट या स्टेटमेंट के टेम्पलेट या तात्कालिकता नहीं होने पर, किसी टेम्पलेट या कॉन्स्टैक्स के विकल्प के लिए कोई मान्य विशेषज्ञता उत्पन्न नहीं की जा सकती है , या

[...]

हां, वास्तव में, आप False<T>पर निर्भर करता है T। समस्या यह है कि एक सामान्य लैम्ब्डा अपने आप में एक टेम्पलेट है, औरFalse<T> लैम्बडा के किसी भी टेम्प्लेट पैरामीटर पर निर्भर नहीं है।

एक के लिए Tहै किFalse<T> गलत है, स्थिर ज़ोर हमेशा गलत हो जाएगा, कोई फर्क नहीं पड़ता जो टेम्पलेट तर्क लैम्ब्डा को भेजा जाता है।

संकलक देख सकता है कि टेम्पलेट के किसी भी तात्कालिकता के लिए operator() , स्थिर मुखर हमेशा वर्तमान टी के लिए ट्रिगर होगा। इसलिए संकलक त्रुटि।

इसके लिए एक समाधान इस पर निर्भर होगा x:

template<typename T>
void foo() {

    auto f = [](auto x) {
        if constexpr(x < 0) {
            static_assert(False<decltype(x)>, "AAA");
        }
    };

    f(std::integral_constant<int, 1>{});
}

जीवंत उदाहरण


13

यहाँ सामान्य नियम [temp.res] / 8 है :

कार्यक्रम बीमार है, कोई नैदानिक ​​की आवश्यकता नहीं है, अगर: कोई टेम्पलेट के लिए कोई वैध विशेषज्ञता उत्पन्न नहीं किया जा सकता है या एक टेम्पलेट के भीतर बयान और टेम्पलेट त्वरित नहीं है तो एक constexpr के प्रतिस्थापन

एक बार जब आप तुरंत foo<T>, static_assertआप अब निर्भर नहीं है। यह बन जाता है static_assert(false)- जेनेरिक लैंबडा के कॉल ऑपरेटर के सभी संभावित इंस्टेंटिएशन के लिए f। यह बीमार है, कोई निदान की आवश्यकता नहीं है। क्लैंग निदान करता है, जीसीसी नहीं करता है। दोनों सही हैं।

ध्यान दें कि यह कोई फर्क नहीं पड़ता कि static_assert यहाँ है खारिज कर दिया।

इसे आसानी से प्रतिस्थापित False<T>करके तय किया जा सकता है False<decltype(x)>

यह static_assertसामान्य लैम्ब्डा के भीतर आश्रित रखता है , और अब हम एक ऐसी स्थिति में पहुंच जाते हैं जहां काल्पनिक रूप से एक मान्य विशेषज्ञता हो सकती है, इसलिए हम अब बीमार नहीं हैं, ndr।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.