How can I output the value of an enum class in C++11? In C++03 it's like this:

#include <iostream>

using namespace std;

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

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

in c++0x this code doesn't compile

#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]'

compiled at Ideone.com

有帮助吗?

解决方案

Unlike an unscoped enumeration, a scoped enumeration is not implicitly convertible to its integer value. You need to explicitly convert it to an integer using a cast:

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

You may want to encapsulate the logic into a function template:

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

used as:

std::cout << as_integer(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;
}

It is possible to get your second example (i.e., the one using a scoped enum) to work using the same syntax as unscoped enums. Furthermore, the solution is generic and will work for all scoped enums, versus writing code for each scoped enum (as shown in the answer provided by @ForEveR).

The solution is to write a generic operator<< function which will work for any scoped enum. The solution employs SFINAE via std::enable_if and is as follows.

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

To write simpler,

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

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

(I'm not allowed to comment yet.) I would suggest the following improvements to the already great answer of James 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);
}

with

  • constexpr: allowing me to use an enum member value as compile-time array size
  • static_assert+is_enum: to 'ensure' compile-time that the function does sth. with enumerations only, as suggested

By the way I'm asking myself: Why should I ever use enum class when I would like to assign number values to my enum members?! Considering the conversion effort.

Perhaps I would then go back to ordinary enum as I suggested here: How to use enums as flags in C++?


Yet another (better) flavor of it without static_assert, based on a suggestion of @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);
}

Following worked for me in 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);
}

You could do something like this:

//outside of main
namespace A
{
    enum A
    {
        a = 0,
        b = 69,
        c = 666
    };
};

//in main:

A::A a = A::c;
std::cout << a << std::endl;
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top