2012-03-26 15 views
27

मेरे पास कुछ सामान्य कोड है जो सी ++ 11 enum class प्रकारों का उपयोग करके निर्दिष्ट ध्वज के साथ काम करता है। एक कदम पर, मैं जानना चाहता हूं कि ध्वज में से किसी भी बिट को सेट किया गया है या नहीं। वर्तमान में, मैं कोड का उपयोग कर रहा:मैं एक बूलियन संदर्भ में एनम कक्षा का उपयोग कैसे कर सकता हूं?

if (flags != static_cast<E>(0)) // Works, but ugly. 

मैं भी एक सब शून्य क्षेत्र के लिए एक विशेष नाम निर्दिष्ट करने के, जो और अधिक पठनीय है, लेकिन यह का उपयोग कर किसी पर अपना नामकरण सम्मेलनों लगाता उपयोगकर्ताओं को बाध्य कर सकते हैं:

if (flags != E::none) // Works, if you manually define none = 0. 

लेकिन इनमें से कोई भी पारंपरिक रूप के रूप में अच्छी तरह से पढ़ता है:

if (flags) // Doesn't work with class enums. 

यह एक बूलियन संदर्भ में एक वर्ग enum मूल्यांकन करने के लिए एक कस्टम समारोह निर्दिष्ट करने के लिए संभव है?

+0

वहाँ एक विशेष कारण आप द्विआधारी झंडे उपयोग नहीं कर सकते है? वे स्वच्छ और कुशल हैं। किसी भी तरह, enum वर्ग मान संख्याओं में परिवर्तित नहीं किया जा सकता है। आपको झंडे का उपयोग करना होगा! = ई :: कोई भी अगर आप गणना कर रहे हैं। आप जानते हैं, आप केवल एक गैर-एनम कक्षा बना सकते हैं और स्टेटिक कॉन्स int का उपयोग कर सकते हैं जो भी = 1, स्थिर कॉन्स int जो भी_else = 2 ... आदि। और केवल कुछ ऑपरेटरों को अधिभारित करें। –

+1

@OrgnlDave: "बाइनरी झंडे" का अर्थ क्या है, बूल? बिटफिल्ड के रूप में वे अक्सर आईबी/यूबी होते हैं और नियमित संरेखण के साथ मैं उन्हें कुशल नहीं कहूंगा, न ही अगर मुझे एक समय में एकाधिक लोगों की प्रतिलिपि बनाना है तो साफ करें। मुझे स्थैतिक स्याही का सुझाव देने में मूल्य नहीं दिखता है, मैं केवल नियमित enum का उपयोग कर सकता हूं और कम से कम एक प्रकार की सुरक्षा प्राप्त कर सकता हूं। –

+0

"मैं सिर्फ नियमित enum का उपयोग कर सकता हूं और कम से कम एक प्रकार की सुरक्षा प्राप्त कर सकता हूं।" फिर आपको यह स्वीकार करना होगा कि इसके साथ आप अब बिट्स के बारे में बात नहीं करेंगे। – GManNickG

उत्तर

14

क्या बूलियन संदर्भ में कक्षा enum का मूल्यांकन करने के लिए एक कस्टम फ़ंक्शन निर्दिष्ट करना संभव है?

हाँ, लेकिन स्वचालित रूप से नहीं। मैन्युअल रूप से फ़ंक्शन को कॉल करना अन्य विकल्पों के मुकाबले कहीं अधिक सुरुचिपूर्ण है।

बस any जैसे एक अच्छा फ़ंक्शन नाम चुनें, और इसे कार्यान्वित करें। ओवरलोड रिज़ॉल्यूशन सुनिश्चित करेगा कि आपका फ़ंक्शन अन्य सभी के साथ अच्छा खेलता है।

bool any(E arg) 
    { return arg != E::none; } 

... 

if (any(flags)) { 
    ... 

मेरे लिए काफी अच्छा लग रहा है।


अद्यतन: अगर आप इस कई गणन प्रकार के लिए लागू करना चाहते हैं, यह टेम्प्लेट की जा सकती है:

template< typename enum_type > // Declare traits type 
struct enum_traits {}; // Don't need to declare all possible traits 

template<> 
struct enum_traits<E> { // Specify traits for "E" 
    static constexpr bool has_any = true; // Only need to specify true traits 
}; 

template< typename enum_type > // SFINAE makes function contingent on trait 
typename std::enable_if< enum_traits<enum_type>::has_any, 
    bool >::type 
any(enum_type e) 
    { return e != enum_type::none; } 

मैं अन्य बातों के लिए तंत्र की इस तरह कभी नहीं का उपयोग करने और किया गया है का सामना करना पड़ा किसी भी दुष्प्रभाव या मुद्दे: v)।

आप विशेषता को छोड़ सकते हैं और enum_type::none == enum_type::none जैसे कुछ को SFINAE स्थिति सेट कर सकते हैं, केवल none और समानता ऑपरेटर की उपस्थिति की जांच के लिए, लेकिन यह कम स्पष्ट और सुरक्षित होगा।

6

नहीं, ऐसा नहीं। रूपांतरण ऑपरेटर सदस्य होना चाहिए, और enums सदस्यों के पास नहीं हो सकता है। मुझे लगता है कि आप सबसे अच्छा कर सकते हैं none के साथ तुलना करें, या यदि none एन्यूमेरेटर नहीं है, तो फ़ंक्शन में static_cast लपेटें।

19

@RMatin की तरह कहते हैं। लेकिन आप को ओवरलोड सकता operator!

bool operator!(E e) { 
    return e == static_cast<E>(0); 
} 

तो तुम एक झंडे क्षेत्र है, तो यह है कि आप !!e मुहावरा

if(!!e) { 
    ... 
} 
6

उपयोग कर सकते हैं (यानी: एक bitfield) मैं दृढ़ता से सलाह आप enum class उपयोग करने के लिए नहीं होता बिटफील्ड के लिए।

मजबूत टाइप किए गए enums मौजूद हैं, ठीक है, दृढ़ता से टाइप किया गया। यह गणनाकर्ताओं को नियमित रूप से पूर्णांक के रूप में निरंतर पूर्णांक नामित करने के अलावा कुछ और बनाता है। विचार यह है कि, यदि आपके पास enum class प्रकार का चर है, तो इसकी सामग्री हमेशा सटीक गणना मानों में से किसी एक से मेल खाती है। यही कारण है कि पूर्णांक या पूर्णांक प्रकारों में कोई अंतर्निहित रूपांतरण नहीं है।

लेकिन यह नहीं है कि आप क्या कर रहे हैं। आप एक बिटफील्ड ले रहे हैं, जो गणना मूल्यों की एक संरचना है। वह संरचना स्वयं उन मूल्यों में से कोई नहीं है; यह उनका संयोजन है। इसलिए, आप झूठ बोल रहे हैं जब आप कहते हैं कि आप enum class प्रकार ले रहे हैं; आप वास्तव में एक हस्ताक्षरित पूर्णांक ले रहे हैं कि enum class गणक में से एक हो सकता है।

उदाहरण के लिए:

enum class Foo 
{ 
    First = 0x01, 
    Second = 0x02, 
    Third = 0x04, 
}; 

Foo val = Foo::First | Foo::Second; 

val इस मामले में First, Second, या Third शामिल नहीं है। आपके पास मजबूत टाइपिंग खो गया है, क्योंकि इसमें कोई भी प्रकार नहीं है।

enum class मूल्यों को स्पष्ट रूप से बूल में परिवर्तित नहीं किया जा सकता है; उन्हें पूर्ण रूप से पूर्णांक में परिवर्तित नहीं किया जा सकता है; और वे निश्चित रूप से उन पर किए गए अधिकांश गणित संचालन नहीं कर सकते हैं। वे अपारदर्शी मान हैं।

और इस प्रकार वे बिटफील्ड के रूप में उपयोग के लिए अनुचित हैं। इस तरह के अनुचित तरीके से enum class का उपयोग करने का प्रयास करने से केवल बहुत सारे कास्टिंग हो जाएंगे। बस एक नियमित पुराने enum का उपयोग करें और खुद को दर्द बचाएं।

+6

"आपने मजबूत टाइपिंग खो दी है, क्योंकि इसमें कोई भी प्रकार नहीं है।" आपका मतलब है, इसमें पूर्वनिर्धारित _values_ में से कोई भी शामिल नहीं है। इसका मतलब यह नहीं है कि मैंने किसी विशेष प्रकार का _type_ उल्लंघन किया है। इसके अलावा, वे _not_ अपारदर्शी मान हैं - उनके मूल्य प्रतिनिधित्व को अंतर्निहित संग्रहण प्रकार के संदर्भ में परिभाषित किया गया है - वे केवल _explicit_ मान हैं। मैं इस सुझाव की सराहना करता हूं कि एनम कक्षाएं यहां सही उपकरण नहीं हैं, लेकिन यह कहकर कि मैं जो चाहता हूं वह "अवैध" है, "उस बिंदु पर स्पष्ट होना चाहिए जहां यह इतना वर्बोज़ है कि यह अब मूल्यवान नहीं है" गलत है। –

+0

@JoeWreschnig: सबसे पहले, मैंने कहा कि मैंने जो कोड लिखा था वह अवैध था, जो यह * है *। दूसरा, आप जो चाहते हैं * के लिए * बहुत स्पष्ट और व्यर्थ जानवरों की आवश्यकता होती है, जो समस्या है जिसे आपने हल करने के लिए कहा है। समाधान उन चीजों का उपयोग करना बंद करना है जिनके लिए स्पष्ट और निर्बाध जानवरों की आवश्यकता होती है। तीसरा, यह एक * अर्थपूर्ण * प्रकार का उल्लंघन है। Enums के लिए मजबूत टाइपिंग का पूरा बिंदु है * कुछ * वाक्य रचनात्मक आश्वासन है कि आपके पास दिए गए मूल्य कानूनी मानों में से एक हैं। हां, लोग झूठ बोल सकते हैं, लेकिन कम से कम उन्हें ऐसा करने के लिए डालना पड़ता है, जिसे अक्सर कुछ छाया करने का संकेत माना जाता है। –

+1

-1: मजेदार, मैंने अभी एक और सवाल का जवाब दिया कि कैसे enum 'झंडे के सेट के लिए आदर्श हैं। आदर्श उदाहरण के साथ समस्या यह है कि 'ऑपरेटर |' अधिभार गुम है। 'enum' प्रकारों को अंतर्निहित प्रकार के मान अर्थशास्त्र का पालन करने के लिए परिभाषित किया गया है, और यदि यह बिटवाई अंकगणितीय का समर्थन करता है, तो सुरक्षा और अंकगणितीय सुरक्षा दोनों अनुकूलित हैं। – Potatoswatter

0

नीचे enum-flags का एक छोटा उदाहरण।

#indlude "enum_flags.h" 

ENUM_FLAGS(foo_t) 
enum class foo_t 
    { 
    none   = 0x00 
    ,a    = 0x01 
    ,b    = 0x02 
    }; 

ENUM_FLAGS(foo2_t) 
enum class foo2_t 
    { 
    none   = 0x00 
    ,d    = 0x01 
    ,e    = 0x02 
    }; 

int _tmain(int argc, _TCHAR* argv[]) 
    { 
    if(flags(foo_t::a & foo_t::b)) {}; 
    // if(flags(foo2_t::d & foo_t::b)) {}; // Type safety test - won't compile if uncomment 
    }; 

ENUM_FLAGS (टी) एक मैक्रो, enum_flags.h में परिभाषित (कम तो 100 लाइनों, कोई प्रतिबंध के साथ प्रयोग करने के लिए स्वतंत्र है)।

6
struct Error { 
    enum { 
     None  = 0, 
     Error1  = 1, 
     Error2  = 2, 
    } Value; 

    /* implicit */ Error(decltype(Value) value) : Value(value) {} 

    explicit operator bool() { 
     return Value != Error::None; 
    } 
}; 

inline bool operator==(Error a, Error b) { 
    return a.Value == b.Value; 
} 

inline bool operator!=(Error a, Error b) { 
    return !(a == b); 
} 

enum अब के लिए कोई अतिभारित ऑपरेटर है, तो एक class या struct में लपेट।

0

मैं आमतौर पर के लिए एकल + ऑपरेटर को ओवरलोड ध्वज की तरह enum classes, ताकि मैं निम्न कर सकते हैं:

#define ENUM_FLAGS (FlagType, UnderlyingType)       \ 
    /* ... */               \ 
    UnderlyingType operator+(const FlagType &flags) {     \ 
      return static_cast<UnderlyingType>(flags)      \ 
    }                 \ 
    /* ... */               \ 
    FlagType operator&(const FlagType &lhs, const FlagType &rhs) {  \ 
      return static_cast<FlagType>(+lhs & +rhs)      \ 
    }                 \ 
    /* ... */               \ 
    FlagType &operator|=(FlagType &lhs, const FlagType &rhs) {   \ 
      return lhs = static_cast<FlagType>(+lhs | +rhs)    \ 
    }                 \ 
    /* ... */               \ 
    /***/ 

// .... 

enum class Flags: std::uint16_t { 
    NoFlag = 0x0000, 
    OneFlag = 0x0001, 
    TwoFlag = 0x0002, 
    // ....  
    LastFlag = 0x8000 
}; 

ENUM_FLAGS(Flags, std::uint16_t) 

auto flagVar = Flags::NoFlag; 

// ... 

flagVar |= Flags::OneFlag; 

// ... 

if (+(flagVar & Flags::OneFlag)) { 
    /// ... 
} 
संबंधित मुद्दे

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