यदि आप स्थैतिक_कास्ट करते हैं, तो Enum class का अमान्य मान?


146

इस C ++ 11 कोड पर विचार करें:

enum class Color : char { red = 0x1, yellow = 0x2 }
// ...
char *data = ReadFile();
Color color = static_cast<Color>(data[0]);

मान लीजिए कि डेटा [0] वास्तव में 100 है। मानक के अनुसार रंग सेट क्या है? विशेष रूप से, अगर मैं बाद में करता हूं

switch (color) {
    // ... red and yellow cases omitted
    default:
        // handle error
        break;
}

क्या मानक गारंटी देता है कि डिफ़ॉल्ट हिट होगा? यदि नहीं, तो यहां एक त्रुटि की जांच करने के लिए उचित, सबसे कुशल, सबसे सुरुचिपूर्ण तरीका क्या है?

संपादित करें:

एक बोनस के रूप में, मानक इस बारे में कोई गारंटी देता है लेकिन सादे एनम के साथ?

जवाबों:


131

मानक के अनुसार रंग सेट क्या है?

C ++ 11 और C ++ 14 मानकों के एक उद्धरण के साथ उत्तर देना:

[Expr.static.cast] / 10

अभिन्न या गणना प्रकार का मान स्पष्ट रूप से एक गणना प्रकार में परिवर्तित किया जा सकता है। मान अपरिवर्तित है यदि मूल मान गणना मूल्यों (7.2) की सीमा के भीतर है। अन्यथा, परिणामी मान अनिर्दिष्ट है (और उस सीमा में नहीं हो सकता है)।

आइए गणना के मानों की सीमा देखें : [dcl.enum] / 7

एक गणना के लिए जिसका अंतर्निहित प्रकार तय हो गया है, गणना के मान अंतर्निहित प्रकार के मूल्य हैं।

CWG 1766 (C ++ 11, C ++ 14) से पहले , इसलिए, data[0] == 100जिसके परिणामस्वरूप परिणाम निर्दिष्ट है (*), और कोई अपरिभाषित व्यवहार (UB) शामिल नहीं है। आम तौर पर, जैसा कि आप अंतर्निहित प्रकार से एन्यूमरेशन प्रकार data[0]तक डालते हैं, यूबी के लिए कोई मूल्य नहीं हो सकता है static_cast

CWG 1766 (C ++ 17) के बाद CWG दोष 1766 देखें । [Expr.static.cast] p10 पैराग्राफ को मजबूत किया गया है, इसलिए अब आप यूबी को लागू कर सकते हैं यदि आप एक मान को एनम के प्रकार के प्रतिनिधित्व योग्य सीमा के बाहर रखते हैं। यह अभी भी प्रश्न में परिदृश्य पर लागू नहीं होता है, क्योंकि data[0]अंतर्निहित प्रकार की गणना है (ऊपर देखें)।

कृपया ध्यान दें कि CWG 1766 को मानक में एक दोष माना जाता है, इसलिए यह कंपाइलर कार्यान्वयनकर्ताओं के लिए उनके C ++ 11 और C ++ 14 संकलन मोड पर लागू करने के लिए स्वीकार किया जाता है।

(*) charकम से कम 8 बिट चौड़ा होना आवश्यक है, लेकिन होना आवश्यक नहीं है unsigned। अधिकतम मूल्य कम से कम 127C99 मानक के अनुलग्नक ई प्रति कम से कम होना आवश्यक है ।


[Expr] / 4 से तुलना करें

यदि किसी अभिव्यक्ति के मूल्यांकन के दौरान, परिणाम गणितीय रूप से परिभाषित नहीं है या अपने प्रकार के लिए प्रतिनिधित्व योग्य मूल्यों की सीमा में नहीं है, तो व्यवहार अपरिभाषित है।

सीडब्ल्यूजी 1766 से पहले, रूपांतरण अभिन्न प्रकार -> गणना प्रकार एक अनिर्दिष्ट मूल्य का उत्पादन कर सकता है । सवाल यह है कि क्या एक अनिर्दिष्ट मूल्य अपने प्रकार के लिए प्रतिनिधित्व योग्य मूल्यों से बाहर हो सकता है? मेरा मानना ​​है कि उत्तर नहीं है - यदि उत्तर हाँ था , तो "इस ऑपरेशन से एक अनिर्दिष्ट मूल्य पैदा होता है" और "इस ऑपरेशन का अपरिभाषित व्यवहार होता है" के बीच गारंटीकृत प्रकारों के लिए आपको मिलने वाली गारंटी में कोई अंतर नहीं होगा।

इसलिए, CWG 1766 से पहले, यहां तक static_cast<Color>(10000)कि UB को भी आमंत्रित नहीं किया जाएगा ; लेकिन CWG 1766 के बाद, यह UB को लागू करता है


अब, switchबयान:

[Stmt.switch] / 2

स्थिति अभिन्न प्रकार, गणना प्रकार या वर्ग प्रकार की होगी। [...] अभिन्न प्रचार किया जाता है।

[Conv.prom] / 4

एक का एक prvalue unscoped गणना प्रकार जिसका अंतर्निहित प्रकार तय हो गई है (7.2) उसके अंतर्निहित प्रकार का एक prvalue में बदला जा सकता। इसके अलावा, अगर इंटीग्रल प्रमोशन को इसके अंतर्निहित प्रकार पर लागू किया जा सकता है, तो एक अनकैप्ड एन्यूमरेशन प्रकार का एक प्रचलन, जिसका अंतर्निहित प्रकार तय हो गया है, को भी प्रमोट किए गए अंतर्निहित प्रकार के एक प्रिव्यू में बदला जा सकता है।

नोट: स्कूप्ड एनम डब्ल्यू / ओ एनम-बेस का अंतर्निहित प्रकार है int। Unscoped enums के लिए अंतर्निहित प्रकार कार्यान्वयन से परिभाषित है, लेकिन से बड़ा नहीं होगा intअगर intसभी प्रगणक के मान हो सकते हैं।

एक असंगत गणना के लिए , यह हमें / 1 तक ले जाता है

एक पूर्णांक के अलावा अन्य प्रकार का एक prvalue bool, char16_t, char32_t, या wchar_tजिसका पूर्णांक रूपांतरण रैंक (4.13) के पद से भी कम है intप्रकार का एक prvalue में बदला जा सकता intहै, तो intस्रोत प्रकार के सभी मूल्यों का प्रतिनिधित्व कर सकते हैं; अन्यथा, स्रोत प्रचलन को प्रकार के एक प्रचलन में परिवर्तित किया जा सकता है unsigned int

एक अप्रकाशित गणना के मामले में , हम intयहां एस के साथ काम करेंगे । के लिए दायरे वाला enumerations ( enum classऔर enum struct), कोई अभिन्न पदोन्नति लागू होता है। किसी भी तरह से, अभिन्न पदोन्नति यूबी के लिए नेतृत्व नहीं करता है, क्योंकि संग्रहीत मूल्य अंतर्निहित प्रकार की सीमा में और सीमा की सीमा में है int

[Stmt.switch] / 5

जब switchकथन निष्पादित किया जाता है, तो इसकी स्थिति का मूल्यांकन किया जाता है और प्रत्येक मामले के साथ तुलना की जाती है। यदि मामले में से एक स्थिरांक स्थिति के मूल्य के बराबर है, तो नियंत्रण को मिलान caseलेबल के बाद बयान में पारित किया जाता है । यदि कोई caseस्थिरांक स्थिति से मेल नहीं खाता है, और यदि कोई defaultलेबल है, तो लेबल द्वारा लेबल किए गए स्टेटमेंट पर नियंत्रण पास हो जाता है default

defaultलेबल मारा जाना चाहिए।

नोट: एक तुलना ऑपरेटर पर एक और नज़र डाल सकता है, लेकिन यह स्पष्ट रूप से संदर्भित "तुलना" में उपयोग नहीं किया जाता है। वास्तव में, यह कोई संकेत नहीं है कि यह हमारे मामले में स्कोप या अनकैप्ड एनम के लिए यूबी को पेश करेगा।


एक बोनस के रूप में, मानक इस बारे में कोई गारंटी देता है लेकिन सादे एनम के साथ?

enumस्कोप किया गया है या नहीं, इससे कोई फर्क नहीं पड़ता। हालाँकि, इससे कोई फ़र्क पड़ता है कि अंतर्निहित प्रकार निश्चित है या नहीं। पूरा [घोषणा.नाम] / 7 है:

एक गणना के लिए जिसका अंतर्निहित प्रकार तय हो गया है, गणना के मान अंतर्निहित प्रकार के मूल्य हैं। अन्यथा, एक गणन जहां के लिए मिनट छोटी से छोटी प्रगणक और है अधिकतम सबसे बड़ा है, गणन के मूल्यों मूल्यों श्रेणी में हैं मिनट के लिए अधिकतम , परिभाषित इस प्रकार है: Let Kहोना 1एक दो के पूरक प्रतिनिधित्व के लिए और 0एक के लिए किसी का पूरक या संकेत-परिमाण प्रतिनिधित्व। b मैक्स अधिकतम से बड़ा या बराबर का सबसे छोटा मान है (| e min | - K; | e max |) और 2 के बराबरएम - 1 , जहांMएक गैर-नकारात्मक पूर्णांक है। मिनट शून्य है अगरमिनट गैर नकारात्मक है और - (ख अधिकतम + K) अन्यथा।

आइए निम्नलिखित गणना पर एक नज़र डालें:

enum ColorUnfixed /* no fixed underlying type */
{
    red = 0x1,
    yellow = 0x2
}

ध्यान दें कि हम इसे स्कूप्ड एनम के रूप में परिभाषित नहीं कर सकते हैं, क्योंकि सभी स्कॉप्ड एनम में अंतर्निहित प्रकार तय किए गए हैं।

सौभाग्य से, ColorUnfixedसबसे छोटा प्रगणक है red = 0x1, इसलिए अधिकतम (| ई मिनट | - K; | ई अधिकतम |) बराबर है । ई अधिकतम | किसी भी मामले में, जो है yellow = 0x2। सबसे छोटा मान या उससे अधिक 2, जो एक सकारात्मक पूर्णांक के लिए 2 M - 1 के बराबर Mहै 3( 2 2 - 1 ) है। (मुझे लगता है कि इरादा सीमा को 1-बिट-चरणों में सीमित करने की अनुमति है।) यह निम्न प्रकार है कि b अधिकतम है 3और bmin है 0

इसलिए, 100की सीमा के बाहर होगा ColorUnfixed, और static_castCWG 1766 से पहले एक अनिर्दिष्ट मूल्य का उत्पादन करेगा और CWG 1766 के बाद अपरिभाषित व्यवहार करेगा।


3
अंतर्निहित प्रकार तय हो गया है, इसलिए गणना मूल्यों ([7.2 [dcl.enum] p7) की सीमा "अंतर्निहित प्रकार के मूल्य" है। 100 निश्चित रूप से एक मूल्य है char, इसलिए "मूल मान अपरिवर्तित (7.2 मान) की सीमा के भीतर है, तो अपरिवर्तित है।" लागू होता है।
केसी

2
मुझे यह देखने के लिए खोजना था कि "यूबी" का क्या मतलब है। ('अपरिभाषित व्यवहार') प्रश्न में अपरिभाषित व्यवहार की संभावना का उल्लेख नहीं किया गया था; इसलिए मेरे साथ ऐसा नहीं हुआ कि आप उस बारे में बात कर रहे हों।
कराडोक

2
@karadoc मैंने शब्द की पहली घटना में एक लिंक जोड़ा है।
dyp

1
इस उत्तर को प्यार करो। उन लोगों के लिए जो बहुत जल्दी स्किमिंग करते हैं, ध्यान दें कि अंतिम वाक्य "इसलिए, 100 सीमा के बाहर होगा ..." केवल तभी लागू होता है यदि कोड अंतर्निहित प्रकार विनिर्देश (इस मामले में चार) को हटाने के लिए संशोधित किया गया था। मुझे लगता है कि वैसे भी इसका मतलब था।
एरिक सेप्पेनन

1
@Ruslan CWG 1766 (या संकल्प) C ++ 14 का हिस्सा नहीं है , लेकिन मुझे लगता है कि यह C ++ 17 का हिस्सा होगा। यहां तक ​​कि C ++ 17 नियमों के साथ, मुझे यह समझ में नहीं आता है कि आपके "आपके उत्तर के अतिरिक्त पाठ को अमान्य" करने का क्या मतलब है। मेरे उत्तर के अन्य भाग मुख्य रूप से इस बात से चिंतित हैं कि "गणना मूल्यों की सीमा" है कि expr.static.cast p10 का जिक्र है।
dp
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.