2011-12-02 14 views
99
#include <iostream> 

struct a 
{ 
    enum LOCAL_A 
    { 
    A1, 
    A2 
    }; 
}; 
enum class b 
{ 
    B1, 
    B2 
}; 

int foo(int input) 
{ 
    return input; 
} 

int main(void) 
{ 
    std::cout<<foo(a::A1)<<std::endl; 
    std::cout<<foo(static_cast<int>(b::B2))<<std::endl; 
} 

a::LOCAL_A दृढ़ता से टाइप किया गया एनम प्राप्त करने की कोशिश कर रहा है, लेकिन इसमें एक छोटा अंतर है: सामान्य enums को पूर्णांक प्रकार में परिवर्तित किया जा सकता है, जबकि दृढ़ता से टाइप किए गए enums इसे बिना कलाकार के कर सकते हैं।int में दृढ़ता से टाइप किए गए enum को स्वचालित रूप से कैसे परिवर्तित करें?

तो, क्या दृढ़ता से टाइप किए गए enum मान को एक पूर्णांक प्रकार में एक कलाकार के बिना परिवर्तित करने का कोई तरीका है? यदि हां, तो कैसे?

उत्तर

77

जोरदार enums कई समस्याएं होंगी और केवल देखते हुए नहीं समस्या को हल करने के रूप में आप अपने प्रश्न में उल्लेख लक्ष्य टाइप किया:

  1. प्रदान करें प्रकार सुरक्षा, इस प्रकार अभिन्न पदोन्नति द्वारा पूर्णांक तक निहित रूपांतरण को नष्ट करने।
  2. अंतर्निहित प्रकार निर्दिष्ट करें।
  3. मजबूत स्कोपिंग प्रदान करें।

इस प्रकार, पूर्ण रूप से दृढ़ता से टाइप किए गए enum को पूर्णांक, या यहां तक ​​कि इसके अंतर्निहित प्रकार को परिवर्तित करना असंभव है - यह विचार है। तो रूपांतरण को स्पष्ट करने के लिए आपको static_cast का उपयोग करना होगा।

अपने ही समस्या देखते हुए तो जाता है और तुम सच में पूर्णांक के लिए निहित पदोन्नति करना चाहते हैं, तो आप बेहतर उपयोग करने की सशक्त संरचना की गुंजाइश के साथ enum टाइप नहीं उस में घोषित किया जाता है।

आशा है कि यह मदद करता है!

12

संख्या कोई प्राकृतिक तरीका है।

वास्तव में, सी ++ 11 में enum class दृढ़ता से टाइप करने के पीछे की प्रेरणाओं में से एक है int पर उनके चुप रूपांतरण को रोकने के लिए।

+0

खुर्शीद Normuradov से जवाब पर एक नज़र डालें। यह 'प्राकृतिक तरीका' आता है और 'सी ++ प्रोग्रामिंग भाषा (चौथा संस्करण)' में उतना ही इरादा है। यह 'स्वचालित तरीके' में नहीं आता है, और यह इसके बारे में अच्छा है। – PapaAtHome

+0

@PapaAtHome मैं static_cast पर उस के लाभ को समझ नहीं पा रहा हूं। टाइपिंग या कोड क्लीननेस में ज्यादा बदलाव नहीं है। यहाँ प्राकृतिक तरीका क्या है? एक समारोह वापसी मूल्य? –

+0

@ user2876962 मेरे लिए लाभ यह है कि यह स्वचालित या 'चुप' नहीं है क्योंकि Iammilind इसे रखता है। यह त्रुटियों को खोजने के लिए भिन्नता को रोकता है। आप अभी भी एक कलाकार कर सकते हैं लेकिन आपको इसके बारे में सोचने के लिए मजबूर होना पड़ता है। इस तरह आप जानते हैं कि आप क्या कर रहे हैं। मेरे लिए यह एक 'सुरक्षित कोडिंग' आदत का हिस्सा है। मैं पसंद करता हूं कि कोई रूपांतरण स्वचालित नहीं किया जाता है, यह एक मौका का एक sliver है कि यह एक त्रुटि पेश कर सकता है। यदि आप मुझसे पूछें तो इस श्रेणी में टाइप सिस्टम से संबंधित सी ++ 11 में काफी कुछ बदलाव आते हैं। – PapaAtHome

104

जैसा कि अन्य ने कहा है, आप एक अंतर्निहित रूपांतरण नहीं कर सकते हैं, और यह डिज़ाइन है।

यदि आप चाहते हैं कि आप कास्ट में अंतर्निहित प्रकार निर्दिष्ट करने की आवश्यकता से बच सकें।

template <typename E> 
constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept { 
    return static_cast<typename std::underlying_type<E>::type>(e); 
} 

std::cout << foo(to_underlying(b::B2)) << std::endl; 
+0

इसे 'स्थैतिक' घोषित करना अच्छा होगा। – ShitalShah

+5

@ShitalShah जो कोई समझ नहीं आता है। –

+0

सुनिश्चित नहीं है कि आपका क्या मतलब है। मैं इसे अभी स्थिर विधि के रूप में उपयोग कर रहा हूं। – ShitalShah

14
#include <cstdlib> 
#include <cstdio> 
#include <cstdint> 

#include <type_traits> 

namespace utils 
{ 

namespace details 
{ 

template< typename E > 
using enable_enum_t = typename std::enable_if< std::is_enum<E>::value, 
               typename std::underlying_type<E>::type 
              >::type; 

} // namespace details 


template< typename E > 
constexpr inline details::enable_enum_t<E> underlying_value(E e)noexcept 
{ 
    return static_cast< typename std::underlying_type<E>::type >(e); 
} 


template< typename E , typename T> 
constexpr inline typename std::enable_if< std::is_enum<E>::value && 
              std::is_integral<T>::value, E 
             >::type 
to_enum(T value) noexcept 
{ 
    return static_cast<E>(value); 
} 

} // namespace utils 




int main() 
{ 
    enum class E{ a = 1, b = 3, c = 5 }; 

    constexpr auto a = utils::underlying_value(E::a); 
    constexpr E b = utils::to_enum<E>(5); 
    constexpr auto bv = utils::underlying_value(b); 

    printf("a = %d, b = %d", a,bv); 
    return 0; 
} 
+2

यह टाइपिंग को कम नहीं करता है या कोड क्लीनर नहीं बनाता है और बड़ी परियोजनाओं में ऐसे निहित रूपांतरण खोजने के लिए इसे कठिन बनाने के साइड इफेक्ट्स हैं। स्टेटिक_कास्ट इन संरचनाओं से व्यापक परियोजना को खोजना आसान होगा। –

10

आशा यह आपके या किसी और में मदद करता है

enum class EnumClass : int //set size for enum 
{ 
    Zero, One, Two, Three, Four 
}; 

union Union //This will allow us to convert 
{ 
    EnumClass ec; 
    int i; 
}; 

int main() 
{ 
using namespace std; 

//convert from strongly typed enum to int 

Union un2; 
un2.ec = EnumClass::Three; 

cout << "un2.i = " << un2.i << endl; 

//convert from int to strongly typed enum 
Union un; 
un.i = 0; 

if(un.ec == EnumClass::Zero) cout << "True" << endl; 

return 0; 
} 
+26

इसे "टाइप पनिंग" कहा जाता है और हालांकि कुछ कंपाइलर्स द्वारा समर्थित पोर्टेबल नहीं है, क्योंकि सी ++ मानक कहता है कि 'un.i'' सेट करने के बाद यह "सक्रिय सदस्य" है और आप केवल संघ के सक्रिय सदस्य को पढ़ सकते हैं । –

+6

@ जोनाथन वाकई आप तकनीकी रूप से सही हैं, लेकिन मैंने कभी एक कंपाइलर नहीं देखा है जहां यह विश्वसनीय रूप से काम नहीं करता है। इस तरह की सामग्री, अज्ञात यूनियन, और #pragma एक बार defacto मानकों हैं। – BigSandwich

+2

कुछ ऐसा क्यों उपयोग करें जो मानक स्पष्ट रूप से मना करता है, जब एक साधारण कलाकार करेगा? यह सिर्फ गलत है। –

3

के रूप में कई ने कहा, कोई तरीका नहीं होता ओवरहेड्स और बहुत अधिक जटिलता को जोड़े बिना कन्वर्ट करने के लिए है, लेकिन आप अपने टाइपिंग एक कम कर सकते हैं थोड़ा और लम्बदास का उपयोग कर इसे बेहतर बनाते हैं यदि कुछ कलाकारों को एक परिदृश्य में थोड़ा अधिक उपयोग किया जाएगा। इससे थोड़ा अधिक फ़ंक्शन ओवरहेड कॉल जोड़ा जाएगा, लेकिन लंबे static_cast तारों की तुलना में कोड को और अधिक पठनीय बना दिया जाएगा जैसा कि नीचे देखा जा सकता है। यह उपयोगी परियोजना व्यापक नहीं हो सकता है, लेकिन केवल कक्षा चौड़ा है।

#include <bitset> 
#include <vector> 

enum class Flags { ......, Total }; 
std::bitset<static_cast<unsigned int>(Total)> MaskVar; 
std::vector<Flags> NewFlags; 

----------- 
auto scui = [](Flags a){return static_cast<unsigned int>(a); }; 

for (auto const& it : NewFlags) 
{ 
    switch (it) 
    { 
    case Flags::Horizontal: 
     MaskVar.set(scui(Flags::Horizontal)); 
     MaskVar.reset(scui(Flags::Vertical)); break; 
    case Flags::Vertical: 
     MaskVar.set(scui(Flags::Vertical)); 
     MaskVar.reset(scui(Flags::Horizontal)); break; 

    case Flags::LongText: 
     MaskVar.set(scui(Flags::LongText)); 
     MaskVar.reset(scui(Flags::ShorTText)); break; 
    case Flags::ShorTText: 
     MaskVar.set(scui(Flags::ShorTText)); 
     MaskVar.reset(scui(Flags::LongText)); break; 

    case Flags::ShowHeading: 
     MaskVar.set(scui(Flags::ShowHeading)); 
     MaskVar.reset(scui(Flags::NoShowHeading)); break; 
    case Flags::NoShowHeading: 
     MaskVar.set(scui(Flags::NoShowHeading)); 
     MaskVar.reset(scui(Flags::ShowHeading)); break; 

    default: 
     break; 
    } 
} 
30

R. Martinho Fernandes द्वारा प्रदान किया जाएगा जवाब का एक C++ 14 संस्करण:

template <typename E> 
constexpr auto to_underlying(E e) noexcept 
{ 
    return static_cast<std::underlying_type_t<E>>(e); 
} 

पिछले जवाब के साथ के रूप में, इस enum और अंतर्निहित प्रकार के किसी भी प्रकार के साथ काम करेंगे। मैंने noexcept कीवर्ड जोड़ा है क्योंकि यह कभी भी अपवाद नहीं फेंक देगा।


अद्यतन
यह भी स्कॉट Meyers द्वारा प्रभावी आधुनिक C++ प्रकट होता है। आइटम 10 देखें (यह पुस्तक की मेरी प्रति में आइटम के अंतिम पृष्ठों में विस्तृत है)।

4

निहित रूपांतरण (डिजाइन द्वारा) की अनुपस्थिति का कारण अन्य उत्तरों में दिया गया था।

template <typename T> 
constexpr auto operator+(T e) noexcept 
    -> std::enable_if_t<std::is_enum<T>::value, std::underlying_type_t<T>> 
{ 
    return static_cast<std::underlying_type_t<T>>(e); 
} 

कौन सा काफी थोड़ा "टाइप भूमि के ऊपर" देता है:

मैं व्यक्तिगत रूप से उनके अंतर्निहित प्रकार के enum वर्गों से रूपांतरण के लिए एकल operator+ का उपयोग

std::cout << foo(+b::B2) << std::endl; 

कहाँ मैं वास्तव में करने के लिए मैक्रो का उपयोग एक शॉट में enums और ऑपरेटर कार्यों बनाएँ।

#define UNSIGNED_ENUM_CLASS(name, ...) enum class name : unsigned { __VA_ARGS__ };\ 
inline constexpr unsigned operator+ (name const val) { return static_cast<unsigned>(val); } 
4

यह देशी enum class के साथ असंभव लगता है, लेकिन शायद आप नकली कर सकते हैं एक enum classclass एक साथ:

इस मामले में,

enum class b 
{ 
    B1, 
    B2 
}; 

के बराबर होगा:

class b { 
private: 
    int underlying; 
public: 
    static constexpr int B1 = 0; 
    static constexpr int B2 = 1; 
    b(int v) : underlying(v) {} 
    operator int() { 
     return underlying; 
    } 
}; 

यह ज्यादातर समकक्ष है मूल enum class पर टी। रिटर्न प्रकार b के साथ आप फ़ंक्शन में b::B1 सीधे वापस कर सकते हैं। आप इसके साथ switch case, आदि

कर सकते हैं और इस उदाहरण की भावना में आप (संभवतः अन्य बातों के साथ साथ) टेम्पलेट का उपयोग कर सकते हैं सामान्यीकरण और किसी भी संभव वस्तु enum class वाक्य रचना द्वारा परिभाषित उपहास करने के लिए।

3

संक्षिप्त उत्तर यह है कि आप ऊपर दिए गए पदों के अनुसार नहीं कर सकते हैं। लेकिन मेरे मामले के लिए, मैं बस नहीं नाम स्थान को अस्त-व्यस्त है लेकिन अभी भी अंतर्निहित रूपांतरण के लिए करना चाहता था, इसलिए मैं अभी किया:

#include <iostream> 

using namespace std; 

namespace Foo { 
    enum { bar, baz }; 
} 

int main() { 
    cout << Foo::bar << endl; // 0 
    cout << Foo::baz << endl; // 1 
    return 0; 
} 

नेमस्पेसिंग तरह के प्रकार के सुरक्षा की एक परत कहते हैं, जबकि मेरे पास नहीं है अंतर्निहित प्रकार के लिए किसी भी enum मूल्य स्थिर स्थिर करने के लिए।

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