140

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

NutCracker
  • 11,485
  • 4
  • 44
  • 68
Adi
  • 2,011
  • 2
  • 15
  • 14
  • 1
    Why you're trying to output enum? enum class is used to don't mix up enum values with int representation – RiaD Jul 10 '12 at 20:31
  • @RiaD What if you evaluate an enum class value in a switch statement and want to catch unhandled values in the default branch, e.g. printing the unhandled value? – stackprotector Oct 22 '21 at 06:24
  • @stackprotector well, I learned few usecases where it's need during last 9 years :) Yours is major of them, of course – RiaD Oct 22 '21 at 08:11
  • Kudos to StackOverflow. – lishrimp Jul 18 '22 at 05:33

9 Answers9

174

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;
James McNellis
  • 348,265
  • 75
  • 913
  • 977
50
#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;
}
ForEveR
  • 55,233
  • 2
  • 119
  • 133
  • I copied this example verbatim and compiled it as `g++ -std=c++0x enum.cpp` but I'm getting a bunch of compiler errors -> http://pastebin.com/JAtLXan9. I also couldn't get the example from @james-mcnellis to compile. – Dennis May 17 '13 at 23:18
  • 4
    @Dennis [underlying_type](http://www.cplusplus.com/reference/type_traits/underlying_type/) is only in C++11 – Deqing Aug 08 '13 at 02:03
  • @Deqing Same for `enum class`. – stackprotector Oct 22 '21 at 06:20
24

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;
}
Community
  • 1
  • 1
James Adkison
  • 9,412
  • 2
  • 29
  • 43
  • You need a `typename` before `std::underlying_type::type`. – uckelman Feb 21 '15 at 14:39
  • @uckelman You're absolutely correct. Thanks for updating my answer. – James Adkison Feb 21 '15 at 14:44
  • this worked for me under clang, but under gcc 4.9.2, this solution fails when chaining << together, with the error `error: cannot bind ‘std::basic_ostream’ lvalue to ‘std::basic_ostream&&’`. this appears to be because when the stream is temporary, the ADL fails, and the above template is not a possibility. any tips? – ofloveandhate Sep 14 '15 at 21:15
  • @ofloveandhate Could you provide a link to an example that produces the issue? I tested the above code in gcc 4.9.2 without any problems and only a slight change, I converted the 3 `cout` statements into a single `cout` statement by chaining the `<<` operators together. See [here](https://goo.gl/lnYkrW) – James Adkison Sep 15 '15 at 00:04
  • let me revise my statement. I was trying to print an enum class contained inside a class, from outside that class. the code above does indeed work for enum classes not contained within a class themselves. – ofloveandhate Sep 15 '15 at 14:42
  • @ofloveandhate I tested by nesting all of the enums above within a `Foo` class and still can't produce your issue, see [here](https://goo.gl/ZqegSS). Perhaps I'm misunderstanding something... without an [MCVE](http://stackoverflow.com/help/mcve) I don't think I can assist any further **but it should work** for enums nested within a class. – James Adkison Sep 15 '15 at 15:25
  • initially i struggled to get the above solution to work for streaming class enum's to Boost.Log trivial logger. The solution is: `using blos = boost::log::record_ostream; template blos& operator<<(typename std::enable_if::value, blos>::type& stream, const T& e) { return stream << static_cast::type>(e); }` – ofloveandhate Jan 20 '16 at 00:59
  • @ofloveandhate It looks like the code in your comment is exactly the code I have in my answer. The only difference I see is that you've replaced `std::ostream` with `blos`, which is exactly what you would need to do in order to provide this functionality for a different class type. Am I missing the point of your comment? – James Adkison Jan 20 '16 at 20:56
  • nope, not at all. this was exactly the point. the Boost.Log documentation indicates that one merely needs to overload << for std::ostream, but for class enum's, i found that insufficient. instead, i had to add an overload for the `blos` i mentioned. i figured i'd share it in case anyone else encounters the issue. – ofloveandhate Jan 21 '16 at 16:31
  • This is the best answer IMO. Worked fine for me with clang. – Oscar Hierro Feb 08 '18 at 18:46
  • Great result, but fyi, no need for the `static_cast` - the value of `underlying_type<...>::type` is some integer type, which can, of course, be put directly into the stream (and the result of the `static_cast` is the same `int` type anyway). – Loss Mentality Nov 29 '18 at 21:21
  • @LossMentality Unless I'm missing your point the cast is required. It's casting the `enum` `e` to its numeric type. Without the cast it would recurse infinitely until **boom!** – James Adkison Nov 30 '18 at 18:56
  • @JamesAdkison So I originally implemented it with the static_cast as well and assumed it was needed. But then I saw another example online somewhere of this same thing, and it wasn't using the cast. I was quite surprised so I tried it... and it worked.... Here you go: https://coliru.stacked-crooked.com/a/ffe8b3415585bf47 A running example. – Loss Mentality Dec 01 '18 at 19:34
  • @LossMentality The code you posted doesn't surprise me. It creates a numeric value from the `enum` and passes it to the stream. As such, it is logically equivalent to a cast. Between the 2 choices I prefer the explicit cast. It is very easy to find explicit C++ casts in code when you want to track down where types are being changed. – James Adkison Dec 03 '18 at 13:51
  • @JamesAdkison Right - the stream can handle all int types. Anyway, I normally prefer explicit casting too. In this case, I'd personally not use it as the type is already there - IMHO, it's a bit like if you have a function `int SomeFunc();` and then later doing `std::cout << static_cast(SomeFunc())` just to make it clear that SomeFunc returns an int. But I never want to argue too hard against explicitness and consistency ;) – Loss Mentality Dec 05 '18 at 19:45
21

To write simpler,

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

int value = static_cast<int>(Color::Blue); // 111
Audrius Meškauskas
  • 20,936
  • 12
  • 75
  • 93
11

(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);
}
Community
  • 1
  • 1
yau
  • 537
  • 6
  • 14
  • Is there a type `T` for which `std::underlying_type::type` exists, but `std::is_enum::value` is false? If not, then the `static_assert` adds no value. – Toby Speight Feb 08 '17 at 08:40
  • 1
    I did not test on all compilers. But, @TobySpeight you are probably right, msvc2013 seems to spit out comprehensible error messages, suggesting a 1-to-1 correspondence between underlying_type_t existing and the type itself being enum. And static_assert isn't even fired. But: the reference says that the behavior of underlying_type is undefined if not provided with a complete enum type. So the static_assert is just a hope to get a maximum comprehensible message in case. Perhaps there are possibilities to force it getting processed earlier/earliest? – yau Feb 08 '17 at 10:15
  • Ah yes, you're right that it's undefined if `Enumeration` is not a complete enum type. In which case, it may already be too late, as it's used in the return type. Perhaps we could specify `std::enable_if::value, std::underlying_type::type>` as the return type? Of course, it's so much easier (and the error messages so much clearer) if you have a compiler with support for Concepts... – Toby Speight Feb 08 '17 at 10:22
  • 1
    Re " Why should I ever use enum class when I would like to assign number values to my enum members?! Considering the conversion effort." I want to specify the exact type once to avoid any accidental narrowing conversions (and to make the static analysis tool happy) in safety critical code – Fred Schoen Sep 28 '22 at 13:10
3

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);
}
NutCracker
  • 11,485
  • 4
  • 44
  • 68
3

Since c++23 there is

std::to_underlying which does the same thing as in all the other answer but it's in std

RiaD
  • 46,822
  • 11
  • 79
  • 123
1

Extending on the excellent answer by James McNellis, if your compiler has support for Concepts and Constraints (introduced in C++20), it could be used to introduce additional compile-time sanity (as in, clearer indication of any incorrect usage) to the function template in the following straighforward manner:

template<typename E>
concept EnumType = std::is_enum_v<E>;

template <EnumType E>
constexpr std::underlying_type_t<E> enumUnderlyingType(E const underlying_type)
{
    return static_cast<std::underlying_type_t<E>>(underlying_type);
}
aydwi
  • 25
  • 5
-2

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;