2017-10-01 25 views
28

this question के संदर्भ में। कोर निरंतर अभिव्यक्ति जिसका उपयोग constexpr वैरिएबल y को प्रारंभ करने के लिए किया जाता है, वह खराब है। एक दिया गया है।यदि कोई कॉन्स्टेक्सर इस कोर निरंतर अभिव्यक्ति त्रुटि को प्रकट नहीं करता है तो क्यों नहीं?

लेकिन अगर मैं एक if constexpr में if बारी करने की कोशिश:

template <typename T> 
void foo() { 
    constexpr int x = -1; 
    if constexpr (x >= 0){ 
     constexpr int y = 1 << x; 
    } 
} 

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

त्रुटि बनी रहती है। जीसीसी 7.2 के साथ अभी भी दे रही है:

error: right operand of shift expression '(1 << -1)' is negative [-fpermissive] 

लेकिन मैंने सोचा था कि अर्थ की जांच एक त्याग शाखा पर unpreformed छोड़ा जाना चाहिए।

एक constexpr लैम्ब्डा के माध्यम से एक अविवेक बनाने में मदद करता है, हालांकि:

template <typename T> 
void foo(){ 
    constexpr int x = -1; 
    constexpr auto p = []() constexpr { return x; }; 
    if constexpr (x >= 0){ 
     constexpr int y = 1<<p(); 
    } 
} 

y पर constexpr विनिर्देशक को बदलने के लिए कैसे त्याग शाखा को चेक किया गया लगता है। क्या यह इरादा व्यवहार है?


@ max66 अन्य कार्यान्वयन की जांच करने के तरह पर्याप्त था। उन्होंने बताया कि त्रुटि दोनों जीसीसी (7.2.0/हेड 8.0.0) और क्लैंग (5.0.0/हेड 6.0.0) के साथ पुन: उत्पन्न होती है।

+0

एक संकलक बग की तरह लगता है। क्या आपने एक और कार्यान्वयन की कोशिश की है? –

+1

@ShacharShemesh - मैं खुद नहीं है। लेकिन पोस्ट के ओपी ने रिपोर्ट की है कि [क्लैंग और एमएसवीसी वही व्यवहार करते हैं] (https://stackoverflow.com/questions/46510531/undefined-behavior-when-constexpr-evaluating-negative-bitshift#comment79975550_46510531)। – StoryTeller

+2

मैं वैनबॉक्स से क्लैंग ++ 3.8.1 – max66

उत्तर

18

मानक के के बारे में अधिक नहीं कहता है। इनके बारे में [stmt.if] में अनिवार्य रूप से दो कथन हैं:

  1. एक संलग्न टेम्पलेट में छोड़े गए बयान तत्काल नहीं हैं।
  2. छोड़े गए कथन से संदर्भित नामों को ओडीआर परिभाषित करने की आवश्यकता नहीं है।

इनमें से कोई भी आपके उपयोग पर लागू नहीं होता है: कंपेलर प्रारंभ होने पर constexpr के बारे में शिकायत करने के लिए सही हैं। ध्यान दें कि जब आप तत्काल का असफल होने के लिए लाभ लेना चाहते हैं तो आपको टेम्पलेट पैरामीटर पर निर्भर स्थिति बनाना होगा: यदि मान टेम्पलेट पैरामीटर पर निर्भर नहीं है तो विफलता तब होती है जब टेम्पलेट परिभाषित ।उदाहरण के लिए, इस कोड को अभी भी विफल:

template <typename T> 
void f() { 
    constexpr int x = -1; 
    if constexpr (x >= 0){ 
     constexpr int y = 1<<x; 
    } 
} 

हालांकि, अगर आप कर x प्रकार T यह ठीक है, तब भी जब fint साथ instantiated है पर निर्भर:

template <typename T> 
void f() { 
    constexpr T x = -1; 
    if constexpr (x >= 0){ 
     constexpr int y = 1<<x; 
    } 
} 
int main() { 
    f<int>(); 
} 
+0

जैसा कि मैंने केरेक को टिप्पणी की है, मेरी पोस्ट में उदाहरण खराब है। मैंने सत्यापित किया कि कोड को टेम्पलेट में ले जाने के बाद यह बनी रहती है। आधार मामला अभी भी एक त्रुटि उत्सर्जित करता है। संकेत नहीं है। मैंने एमसीवीई अपडेट किया है। असुविधा के लिए खेद है। – StoryTeller

+2

@StoryTeller: मैंने यह स्पष्ट करने के लिए अपनी प्रतिक्रिया अपडेट की कि टेम्पलेट का केवल * तत्काल * प्रभावित है। आपको प्राप्त त्रुटि टेम्पलेट की * परिभाषा * के दौरान होती है! –

+0

@ डाइटमार कुहल: बहुत अच्छा बिंदु - गैर-निर्भर निर्माण की जांच टेम्पलेट परिभाषा का हिस्सा है, किसी एक टेम्पलेट तत्काल की नहीं, इसलिए छोड़े गए हाथ की गैर-तात्कालिकता वास्तव में एक लाल हेरिंग है। –

5

मुझे यकीन नहीं है कि आप शाखा की जांच क्यों नहीं कर सकते हैं। केवल समय एक है, तो शाखा "की जाँच नहीं की है" जब यह, एक टेम्पलेट का हिस्सा है और नहीं instantiated है के रूप में प्रति [stmt.if] p2:

एक संलग्न की इन्स्टेन्शियशन के दौरान ( इकाई टेम्प्लेट खंड 17), यदि स्थिति इसके तत्कालता के बाद मूल्य-निर्भर नहीं है, तो छोड़ा गया सबस्टेटमेंट (यदि कोई है) तत्काल नहीं है।

आपका कोड ऐसी स्थिति में प्रतीत नहीं होता है जहां यह लागू होता है।

+1

मैं अपने [एमसीवी] गरीब होने के लिए स्वीकार करता हूं। [लेकिन कोड को टेम्पलेट में ले जाने के बाद त्रुटि बनी रहती है] (https://wandbox.org/permlink/ASFlaJjyMbXqfRtt) (हालांकि लैम्ब्डा के साथ नहीं)। तो मैं अपना प्रश्न अपडेट कर दूंगा। इस उत्तर को अमान्य करने के लिए खेद है। – StoryTeller

+3

@StoryTeller: कोई चिंता नहीं। गहराई से इस तरह की नई सुविधाओं का पता लगाना अच्छा है। –

10

ध्यान दें कि बयान के लिए Constexpr If द्वारा छोड़ा गया:

छोड़े गए कथन को हर संभावित विशेषज्ञता के लिए बीमार नहीं बनाया जा सकता:

समस्या को ठीक करने के लिए आप टेम्पलेट पैरामीटर के आधार पर कथन कर सकते हैं, उदा।

template<typename T, int X> struct dependent_value { constexpr static int V = X; }; 

template <typename T> 
void foo() { 
    constexpr int x = -1; 
    if constexpr (x >= 0){ 
     constexpr int y = 1 << dependent_value<T, x>::V; 
    } 
} 

LIVE

संबंधित मुद्दे