2012-07-10 20 views
56

में एनम क्लास के मान को कैसे आउटपुट कर सकता हूं I C++ 11 में enum class के मान को कैसे आउटपुट कर सकता हूं? सी ++ 03 में यह इस तरह है:मैं सी ++ 11

#include <iostream> 

using namespace std; 

enum A { 
    a = 1, 
    b = 69, 
    c= 666 
}; 

int main() { 
    A a = A::c; 
    cout << a << endl; 
} 

ग में ++ 0x इस कोड संकलन नहीं है

#include <iostream> 

using namespace std; 

enum class A { 
    a = 1, 
    b = 69, 
    c= 666 
}; 

int main() { 
    A a = A::c; 
    cout << a << endl; 
} 


prog.cpp:13:11: error: cannot bind 'std::ostream' lvalue to 'std::basic_ostream<char>&&' 
/usr/lib/gcc/i686-pc-linux-gnu/4.5.1/../../../../include/c++/4.5.1/ostream:579:5: error: initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char, _Traits = std::char_traits<char>, _Tp = A]' 

एक unscoped गणन के विपरीत Ideone.com

+1

आप एनम आउटपुट करने का प्रयास क्यों कर रहे हैं? enum क्लास का उपयोग int प्रतिनिधित्व के साथ enum मानों को मिश्रण नहीं करने के लिए किया जाता है – RiaD

उत्तर

75

पर संकलित, एक दायरे वाले गणन है निहित इसके पूर्णांक मान के लिए परिवर्तनीय नहीं है। आप की जरूरत स्पष्ट रूप से एक डाली का उपयोग कर एक पूर्णांक के लिए परिवर्तित:

template <typename Enumeration> 
auto as_integer(Enumeration const value) 
    -> typename std::underlying_type<Enumeration>::type 
{ 
    return static_cast<typename std::underlying_type<Enumeration>::type>(value); 
} 

रूप में इस्तेमाल किया:

std::cout << as_integer(a) << std::endl; 
+1

क्या कोई कारण पीछे पीछे वापसी प्रकार वाक्यविन्यास का उपयोग करता है? –

+0

@ निकोलबोलस: मैंने अपने ओपन-सोर्स लाइब्रेरीज़ में से एक से 'as_integer' की प्रतिलिपि बनाई है, CxxReflect (देखें [enumeration.hpp] (http://cxxreflect.codeplex.com/SourceControl/changeset/view/8ffbb562ad38#cxxreflect%2fcore%2fenumeration .hpp))। पुस्तकालय लगातार हर जगह पीछे पीछे वापसी प्रकार का उपयोग करता है। स्थिरता के लिए। –

+6

हालांकि यह 2 साल देर हो चुकी है, अगर कोई अन्य व्यक्ति इस प्रश्न को देखता है तो आप केवल कास्ट तकनीक विधि का उपयोग कर सकते हैं और पूर्णांक प्राप्त करने के लिए "static_cast (मान)" को कॉल कर सकते हैं या "static_cast (intValue)" को enum प्राप्त करने के लिए मूल्य। बस ध्यान रखें कि int से enum या enum से enum तक जाने से समस्याएं हो सकती हैं और आम तौर पर आमतौर पर डिज़ाइन बग का संकेत होता है। –

26

std::cout << static_cast<std::underlying_type<A>::type>(a) << std::endl; 

आप एक समारोह टेम्पलेट में तर्क संपुटित कर सकते हैं

#include <iostream> 
#include <type_traits> 

using namespace std; 

enum class A { 
    a = 1, 
    b = 69, 
    c= 666 
}; 

std::ostream& operator << (std::ostream& os, const A& obj) 
{ 
    os << static_cast<std::underlying_type<A>::type>(obj); 
    return os; 
} 

int main() { 
    A a = A::c; 
    cout << a << endl; 
} 
+0

मैंने इस उदाहरण verbatim की प्रतिलिपि बनाई और इसे 'g ++ -std = C++ 0x enum.cpp' के रूप में संकलित किया लेकिन मुझे कंपाइलर त्रुटियों का एक गुच्छा मिल रहा है -> http://pastebin.com/JAtLXan9। मैं संकलन के लिए @ जेम्स-मैकनेलिस से भी उदाहरण नहीं प्राप्त कर सका। – Dennis

+3

@ डेनिस [अंतर्निहित_type] (http://www.cplusplus.com/reference/type_traits/underlying_type/) केवल सी ++ 11 – Deqing

9

(मुझे अभी तक टिप्पणी करने की अनुमति नहीं है।) मैं निम्नलिखित सुधारों का सुझाव दूंगा जेम्स McNellis की पहले से ही महान जवाब:

template <typename Enumeration> 
constexpr auto as_integer(Enumeration const value) 
    -> typename std::underlying_type<Enumeration>::type 
{ 
    static_assert(std::is_enum<Enumeration>::value, "parameter is not of type enum or enum class"); 
    return static_cast<typename std::underlying_type<Enumeration>::type>(value); 
} 

  • constexpr साथ: मुझे संकलन समय सरणी आकार के रूप में एक enum सदस्य मूल्य
  • static_assert + is_enum उपयोग करने की अनुमति: 'सुनिश्चित' के लिए संकलन समय जब समारोह sth करता है। enumerations के साथ ही, के रूप में सुझाव दिया

तरह से मैं अपने आप को पूछ रहा हूँ द्वारा: क्यों मैं कभी enum class का उपयोग करना चाहिए जब मैं अपने enum सदस्यों को नंबर प्रदान करना चाहते हैं ?! रूपांतरण प्रयास को ध्यान में रखते हुए।

शायद मैं तो साधारण enum के लिए वापस जाने के रूप में मैं यहाँ का सुझाव दिया: How to use enums as flags in C++?


फिर भी एक और (बेहतर) static_assert बिना इसके बारे में स्वाद, @TobySpeight के सुझाव के आधार पर:

template <typename Enumeration> 
constexpr std::enable_if_t<std::is_enum<Enumeration>::value, 
std::underlying_type_t<Enumeration>> as_number(const Enumeration value) 
{ 
    return static_cast<std::underlying_type_t<Enumeration>>(value); 
} 
+0

में है, क्या कोई प्रकार 'टी' है जिसके लिए' std :: underlying_type :: प्रकार 'मौजूद है, लेकिन' std :: is_enum :: value' गलत है? यदि नहीं, तो 'static_assert' कोई मूल्य नहीं जोड़ता है। –

+0

मैंने सभी कंपाइलरों पर परीक्षण नहीं किया। लेकिन, @TobySpeight आप शायद सही हैं, msvc2013 समझने योग्य त्रुटि संदेशों को थूकना प्रतीत होता है, जो अंतर्निहित_type_t मौजूदा के बीच 1-से-1 पत्राचार का सुझाव देता है और प्रकार स्वयं enum है। और static_assert भी निकाल दिया नहीं है। लेकिन: संदर्भ कहता है कि पूर्ण enum प्रकार के साथ प्रदान नहीं किया गया है, तो underlying_type का व्यवहार अपरिभाषित है। तो static_assert केवल मामले में अधिकतम समझदार संदेश प्राप्त करने की उम्मीद है। शायद इसे पहले/जल्द से जल्द संसाधित करने के लिए मजबूर करने की संभावनाएं हैं? – yau

+0

आह हाँ, आप सही हैं कि अगर 'गणना' एक पूर्ण enum प्रकार नहीं है तो यह अनिर्धारित है। इस मामले में, यह बहुत देर हो चुकी है, क्योंकि इसका उपयोग रिटर्न प्रकार में किया जाता है। शायद हम 'std :: enable_if :: value, std :: underlying_type :: प्रकार>' वापसी प्रकार के रूप में निर्दिष्ट कर सकते हैं? बेशक, यह बहुत आसान है (और त्रुटि संदेश इतने स्पष्ट हैं) यदि आपके पास अवधारणाओं के लिए समर्थन वाला कंपाइलर है ... –

14

असम्पीडित enums के समान वाक्यविन्यास का उपयोग करके काम करने के लिए अपना दूसरा उदाहरण (यानी, एक स्कोप्ड एनम का उपयोग करके) प्राप्त करना संभव है। इसके अलावा, समाधान सामान्य है और सभी स्कोप्ड एनम के लिए काम करेगा, प्रत्येक स्कोप्ड एनम के लिए लेखन कोड बनाम (जैसा कि @ForEveR द्वारा प्रदत्त answer में दिखाया गया है)।

समाधान एक सामान्य operator<< फ़ंक्शन लिखना है जो किसी भी स्कॉम्ड एनम के लिए काम करेगा। समाधान SFINAEstd::enable_if के माध्यम से कार्य करता है और निम्नानुसार है।

#include <iostream> 
#include <type_traits> 

// Scoped enum 
enum class Color 
{ 
    Red, 
    Green, 
    Blue 
}; 

// Unscoped enum 
enum Orientation 
{ 
    Horizontal, 
    Vertical 
}; 

// Another scoped enum 
enum class ExecStatus 
{ 
    Idle, 
    Started, 
    Running 
}; 

template<typename T> 
std::ostream& operator<<(typename std::enable_if<std::is_enum<T>::value, std::ostream>::type& stream, const T& e) 
{ 
    return stream << static_cast<typename std::underlying_type<T>::type>(e); 
} 

int main() 
{ 
    std::cout << Color::Blue << "\n"; 
    std::cout << Vertical << "\n"; 
    std::cout << ExecStatus::Running << "\n"; 
    return 0; 
} 
+0

आपको 'std :: underlying_type :: टाइप' से पहले 'टाइपनाम' की आवश्यकता है। – uckelman

+0

@uckelman आप बिल्कुल सही हैं। मेरा जवाब अपडेट करने के लिए धन्यवाद। –

+0

यह मेरे लिए क्लैंग के तहत काम करता था, लेकिन जीसीसी 4.9.2 के तहत, यह समाधान << साथ, त्रुटि त्रुटि के साथ विफल रहता है: std :: basic_ostream 'lvalue to' std :: basic_ostream && ' '। ऐसा प्रतीत होता है क्योंकि जब स्ट्रीम अस्थायी होती है, तो एडीएल विफल रहता है, और उपर्युक्त टेम्पलेट एक संभावना नहीं है। कोई सुझाव? – ofloveandhate

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

  • कोई संबंधित समस्या नहीं^_^