2016-09-12 6 views
9

को देखते हुए enum class val { foo = 1, bar = 2, baz = 4 };क्या यह enum मानों को डालने के लिए कानूनी है क्या enum द्वारा प्रतिनिधित्व योग्य नहीं है?

यह परिभाषित करना संभव है:

val operator|(val x, val y) 
{ 
    return static_cast<val>(static_cast<int>(x) | static_cast<int>(y)); 
} 

हालांकि, यह ऐसा करने के लिए अर्थ की दृष्टि से सही है?

मैं, कोई की ओर झुकाव रहा हूँ के रूप में निम्नलिखित में प्रदर्शन किया, मालूम होता है उदाहरण के लिए अच्छी तरह से व्यवहार कर:

int convert(val x) 
{ 
    switch(x) 
    { 
    case val::foo: return 42; 
    case val::bar: return 53; 
    case val::baz: return 64; 
    } 
} 

convert(val::foo | val::bar) कॉलिंग 0 वापस आ जाएगी जब जी ++ और बजना साथ ++ विभाजन गलती के साथ संकलित।

Here जी ++ संस्करण है। और here क्लैंग ++ संस्करण है।

मेरा प्रश्न है दो गुना:

  1. यह एक enum है कि एक प्रगणक द्वारा प्रतिनिधित्व नहीं कर रहे हैं में शब्दार्थ दुकान मूल्यों के लिए सही है? मानक से अंश स्वागत है।

1.a उपरोक्त लिंक किए गए उदाहरणों, जी ++ या क्लैंग ++ में कौन सा कंपाइलर सही है?

  1. क्या सी ++ में झंडे का प्रतिनिधित्व करने के लिए कोई मानक (या प्रस्तावित) तरीका है?

मैं कई संभव कार्यान्वयन के बारे में सोच सकते हैं:

enum class val { foo, bar, baz, size }; 
using val_flags = std::set<val>; // (1) 
using val_flags = std::vector<bool>; // (2) 
using val_flags = std::bitset<val::size>; // (3) 
using val_flags = std::underlying_type<val>::type; // (4) 

अद्यतन:

आप सभी अपने जवाब के लिए धन्यवाद। मैं अपने पुराने एनम ऑपरेटर टेम्पलेट को पुनर्जीवित करना समाप्त कर दिया। में मामला किसी को दिलचस्पी है, इसे यहाँ पाया जा सकता है: github.com

+2

मुझे लगता है कि तुम वहाँ अपरिभाषित व्यवहार हो सकता है कर सकते हैं (यह मानते हुए 'convert' कानूनी है):' x' किसी भी मूल्य 'val' में फिट नहीं करता है, और तो तुम लापता वापसी कथन के कारण अपरिभाषित व्यवहार प्राप्त करें। – Rakete1111

+0

एकमात्र समस्या जो मैं यहां देखता हूं वह यह है कि 'int कन्वर्ट (वैल एक्स)' की संभावना किसी भी मूल्य को वापस नहीं करने की संभावना है। मुझे पूरा यकीन है कि आपके कंपाइलर ने इसके बारे में चेतावनी जारी की है। – Havenard

उत्तर

6

निम्नलिखित, मालूम होता है अच्छी तरह से व्यवहार कर उदाहरण:

यह नहीं है, लेकिन एक मामूली परिवर्तन कर:

int convert(val x) 
{ 
    switch(x) 
    { 
    case val::foo: return 42; 
    case val::bar: return 53; 
    case val::baz: return 64; 
    } 

    return 9; // ADDED THIS LINE 
} 

और सब कुछ अच्छा होगा। एक वैकल्पिक फिक्स default: केस का उपयोग करना होगा और वहां वापस आना होगा।

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

enum में मूल्य रखने के अर्थशास्त्र जो बिटवाई हैं या गणना मूल्यों के संयोजन अच्छी तरह से परिभाषित और गारंटीकृत हैं। मानक के लिए आवश्यक है कि enum के उदाहरण किसी भी पूर्णांक मान को संग्रहीत कर सकें, जिसमें परिभाषित मूल्यों में से किसी भी संख्या से अधिक बिट्स का उपयोग नहीं किया गया है, जिसमें सभी bitwise-OR संयोजन शामिल हैं।औपचारिक यह कहना उपयोग की गई भाषा थोड़ा गंदा है, लेकिन यहाँ यह है (ध्यान दें कि आपके मामले के एक enum class है, ये हमेशा तय कर दी है अंतर्निहित प्रकार और पहला वाक्य लागू होता है):

एक गणन जिसका अंतर्निहित प्रकार के लिए तय किया गया है, गणना के मूल्य अंतर्निहित प्रकार के मान हैं। अन्यथा, एक गणन जहां ई मिनट छोटी से छोटी प्रगणक और ई है के लिए अधिकतम सबसे बड़ा है, गणन के मूल्यों रेंज ख में मानों मिनट अधिकतम, डी फाई नेड ख के लिए इस प्रकार हैं: चलो के दो के पूरक प्रतिनिधित्व के लिए 1 हो और 0 के पूरक या साइन-आयाम प्रतिनिधित्व के लिए 0 हो। ख अधिकतम सबसे छोटा मान से बड़ा या अधिकतम के बराबर है (| ई मिनट | - कश्मीर, | ई मिनट |) और 2 एम के बराबर - 1, जहां एम एक गैर नकारात्मक है पूर्णांक। बी मिनट शून्य है यदि ई मिनट गैर-ऋणात्मक है और - (बी अधिकतम + के) अन्यथा। का आकार गणना के प्रकार के सभी मानों को पकड़ने के लिए काफी छोटा सा क्षेत्रफल अधिकतम (एम, 1) है यदि बी मिनट शून्य और एम + 1 अन्यथा है। एक गणना को संभव बनाना संभव है जिसमें उसके किसी भी गणक द्वारा परिभाषित मूल्य नहीं हैं। यदि प्रगणक-सूची खाली है, गणन के मूल्यों के रूप में अगर गणन मूल्य के साथ एक एकल प्रगणक पड़ा हो 0.

(n4582 से, अनुभाग 7,2 [dcl.enum])


6.6.3 से [stmt.return]:

एक सीवी के साथ एक निर्माता, एक नाशक, या एक समारोह के अंत की ओर बहने वालीvoid रिटर्न प्रकार बिना किसी ऑपरेंड के रिटर्न के बराबर है। अन्यथा, मुख्य (3.6.1) के अलावा किसी अन्य कार्य के अंत में बहने वाले परिणाम में परिणाम बहते हैं।

+0

या आप अंतर्निहित प्रकार के बारे में स्पष्ट हो सकते हैं और 'enum class val: std :: uint16_t {...};' या जो भी हो। यदि मैं कच्चे मूल्यों पर थोड़ा सा संचालन करना चाहता हूं, तो मैं एक 'हस्ताक्षरित' प्रकार का उपयोग करना पसंद करूंगा। – 5gon12eder

+0

@ बेन, आपके उत्तर के लिए धन्यवाद। तो, इससे दूर लेना यह है कि यह enum के सभी गणकों का परीक्षण करने के लिए पर्याप्त नहीं है? क्या किसी ने हमेशा एक 'डिफ़ॉल्ट:' खंड (या समान) जोड़ना चाहिए यदि किसी ने मनमाना मूल्य पारित किया हो, तो गणनाकर्ता द्वारा कवर न किया जाए? –

+0

@InnocentBystander इस विशेष मामले में, एक डिफ़ॉल्ट मामला पर्याप्त होगा। अंगूठे का नियम हमेशा कुछ वापस करना है, इससे कोई फर्क नहीं पड़ता कि आप क्या धारणा मानते हैं। अंगूठे का एक अन्य नियम आपके कंपाइलर चेतावनियों को पढ़ना है, क्योंकि यह आपको बताएगा कि क्या आप कुछ वापस करना भूल गए हैं। – Nelfeal

3

यह अर्थ की दृष्टि से एक enum है कि एक प्रगणक द्वारा प्रतिनिधित्व नहीं कर रहे हैं में दुकान मूल्यों के लिए सही है? मानक से अंश स्वागत है।

हाँ यदि मूल्य गणना की सीमा में है। बेन वोगेट ने मानक से एक अंश प्रदान किया। मैं cppreference पर देखना पसंद करता हूं क्योंकि मुझे इसे और अधिक पठनीय लगता है (हालांकि इसमें समान आधिकारिक मान नहीं है)।

पूर्णांक, फ़्लोटिंग-पॉइंट, और अन्य गणना प्रकारों के मानों को परिवर्तित किया जा सकता है, जैसे static_cast, किसी भी गणना प्रकार के लिए। नतीजा निर्दिष्ट नहीं है (सी ++ 17 तक) अपरिभाषित व्यवहार (सी ++ 17 के बाद से) यदि मूल्य, गणना के अंतर्निहित प्रकार में परिवर्तित किया गया है, तो इस गणना की सीमा से बाहर है। यदि अंतर्निहित प्रकार तय किया गया है, तो सीमा अंतर्निहित प्रकार की सीमा है। यदि अंतर्निहित प्रकार तय नहीं किया गया है, तो सीमा सभी छोटे मान फ़ील्ड के लिए संभव है जो लक्ष्य गणना के सभी गणक को पकड़ने के लिए पर्याप्त हैं। ध्यान दें कि इस तरह के रूपांतरण के बाद मूल्य टाइप के लिए परिभाषित नामित समकक्षों में से किसी के बराबर नहीं हो सकता है।

कौन सा संकलक ऊपर लिंक उदाहरण में, जी ++ या बजना ++ सही है?

समस्या यह है कि आपका कोड अपरिभाषित व्यवहार का आह्वान करता है, लेकिन तर्कों से संबंधित किसी कारण के लिए, टिप्पणियों में और बेन वोगेट द्वारा इंगित किया गया है। तो दोनों कंपाइलर्स सही हैं।

ध्यान दें कि आपको इन व्यवहारों के प्रयोग के लिए वास्तव में convert फ़ंक्शन की आवश्यकता नहीं है।

enum class val { foo = 1, bar = 2, baz = 4 }; 

val operator|(val x, val y) { 
    return static_cast<val>(static_cast<int>(x) | static_cast<int>(y)); 
} 

int main() { 
    std::cout << static_cast<int>(val::foo | val::bar); // prints 3 
} 

Live example

एक मानक (या प्रस्तावित) जिस तरह से सी ++ में झंडे का प्रतिनिधित्व करने के है?

मैं दायरे के लिए संरचना (या कक्षा) में स्थैतिक constexpr चर के लिए जाना होगा।

struct Flags { 
    static constexpr unsigned int foo = 0x01; 
    static constexpr unsigned int bar = 0x02; 
    static constexpr unsigned int baz = 0x04; 
}; 
+1

लेकिन ध्यान दें कि प्रतीकात्मक स्थिरांक दृष्टिकोण प्रकार की सुरक्षा नहीं देता है या ओवरलोडिंग की अनुमति नहीं देता है। –

+0

@BenVoigt अच्छा बिंदु, हालांकि झंडे से निपटने के दौरान मुझे कभी जरूरत नहीं है। ऐसा कहा जा रहा है कि, मैं अक्सर झंडे से निपट नहीं रहा हूं, मुख्य रूप से क्योंकि आमतौर पर बेहतर समाधान होते हैं। – Nelfeal

2
अन्य उत्तर की तरफ

(जो पहले से ही समस्या ने बताया), तो आप झंडे का एक सेट की आवश्यकता है, एक std::bitset पर विचार करें, और अंततः एक enum का उपयोग बिट्स (न कि उसका weigths) को नाम देने के लिए, जैसे

enum flags_names { f0, f1, f2, f3, NFlags } 
typedef std::bitset<NFlags> flags; 

अब आप

flags fs; 
fs[f0] = true; fs[f2] = false; 
if(fs[f0]) ... 
etc. 
+0

धन्यवाद एमिलियो।'बिट्ससेट 'या' वेक्टर 'या' 'सेट करने के साथ मेरे पास एकमात्र समस्या है कि वे' enum 'के रूप में हल्के वजन वाले नहीं हैं। जबकि एक रजिस्टर में enums पारित किया जा सकता है, अन्य सभी समाधानों को स्मृति आवंटन की आवश्यकता होती है, संदर्भ द्वारा गुजरती है, आदि –

+0

मैं 'बिट्ससेट 'के लिए बसने वाला था क्योंकि मैंने देखा है कि इसके कई कार्य' constexpr' हैं। हालांकि, मेरे लिए असली सौदा-ब्रेकर इसे 'प्रारंभकर्ता_सूची' से बनाने में असमर्थ था। कुछ ऐसा: 'झंडे = {एफ 0, एफ 2}'। वैसे भी आपके उत्तर के लिए और मेरे द्वारा +1 –

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