मैं C ++ 11 में एक एनम वर्ग के मूल्य को कैसे आउटपुट कर सकता हूं


96

मैं enum classC ++ 11 में मूल्य का उत्पादन कैसे कर सकता हूं ? C ++ 03 में यह इस प्रकार है:

#include <iostream>

using namespace std;

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

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

c ++ 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]'

Ideone.com पर संकलित


1
आप एनम आउटपुट करने की कोशिश क्यों कर रहे हैं? Enum वर्ग का उपयोग
इंटिमेट

जवाबों:


122

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

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

आप फ़ंक्शन टेम्पलेट में तर्क को एनकोड करना चाहते हैं:

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;

3
वहाँ एक कारण यह अनुगामी वापसी प्रकार वाक्यविन्यास का उपयोग करता है?
निकोल बोलस

3
@ नाइकोलोलस: मैंने as_integerअपने एक ओपन-सोर्स लाइब्रेरी, CxxReflect ( enumeration.pp ) देखें । पुस्तकालय हर जगह, लगातार रिटर्न रिटर्न प्रकार का उपयोग करता है। स्थिरता के लिए।
जेम्स मैकनेलिस

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

4
int (मान) और A (intValue) भी काम करते हैं, बदसूरत कोण कोष्ठक के बिना।
अंगूर

4
as_integerको परिभाषित किया जा सकता है constexprताकि इसे संदर्भों में उपयोग किया जा सके जहां निरंतर अभिव्यक्ति की आवश्यकता हो।
नवाज

39
#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;
}

मैंने इस उदाहरण को शब्दशः कॉपी किया और इसे संकलित किया g++ -std=c++0x enum.cppलेकिन मुझे कंपाइलर त्रुटियों का एक गुच्छा मिल रहा है -> pastebin.com/JAtLXan9 । मैं संकलन करने के लिए @ james-mcnellis से उदाहरण भी प्राप्त नहीं कर सका।
डेनिस

4
@ डेनिस अंतर्निहित_टाइप केवल C ++ 11 में है
Deqing

23

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

इसका समाधान यह है कि जेनेरिक operator<<फ़ंक्शन लिखें, जो किसी भी स्कूप्ड एनम के लिए काम करेगा। समाधान SFINAE के माध्यम से कार्यरत है std::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;
}

आपको typenameपहले की जरूरत है std::underlying_type<T>::type
कोयलमैन

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

यह मेरे लिए क्लेंग के तहत काम करता है, लेकिन 4.9.2 के तहत, यह समाधान विफल रहता है जब << एक साथ, त्रुटि के साथ, पीछा करते हुए error: cannot bind ‘std::basic_ostream<char>’ lvalue to ‘std::basic_ostream<char>&&’। ऐसा प्रतीत होता है क्योंकि जब धारा अस्थायी होती है, तो ADL विफल हो जाता है, और उपरोक्त टेम्पलेट संभावना नहीं है। कोई सुझाव?
कपालभाती

@ofloveandhate क्या आप इस मुद्दे को उत्पन्न करने वाले उदाहरण के लिए एक लिंक प्रदान कर सकते हैं? मैंने बिना किसी समस्या के केवल 4.9.2 में उपर्युक्त कोड का परीक्षण किया और केवल एक मामूली परिवर्तन, मैंने 3 coutबयानों को एक साथ संचालकों का coutपीछा करते हुए एक बयान में बदल दिया <<यहां
जेम्स एडिसन

मुझे मेरे कथन को संशोधित करने दो। मैं उस वर्ग के बाहर से, एक वर्ग के अंदर समाहित एनम वर्ग को मुद्रित करने का प्रयास कर रहा था। उपरोक्त कोड वास्तव में एनम वर्ग के लिए काम करता है जो स्वयं एक वर्ग के भीतर निहित नहीं है।
१२:४२ पर क्लोविएंडेट

10

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

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: मुझे संकलन-समय सरणी आकार के रूप में एनम सदस्य मान का उपयोग करने की अनुमति देता है
  • static_assert+ is_enum: संकलन-समय को 'सुनिश्चित' करने के लिए कि फ़ंक्शन sth करता है। सुझाव के अनुसार केवल गणना के साथ

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

शायद तब मैं फिर से सामान्य हो जाऊंगा enumजैसा कि मैंने यहां सुझाया है: सी ++ में झंडे के रूप में एनम का उपयोग कैसे करें?


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

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);
}

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

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

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

6

सरल लिखने के लिए,

enum class Color
{
    Red = 1,
    Green = 11,
    Blue = 111
};

int value = static_cast<int>(Color::Blue); // 111

जब एनम स्पष्ट रूप से एक अंतर्निहित प्रकार दिया जाता है तो यह काम नहीं करेगा
जेम्स

3

C ++ 11 में मेरे लिए काम करने के बाद:

template <typename Enum>
constexpr typename std::enable_if<std::is_enum<Enum>::value,
                                  typename std::underlying_type<Enum>::type>::type
to_integral(Enum const& value) {
    return static_cast<typename std::underlying_type<Enum>::type>(value);
}

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.