Reputation: 2051
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
Upvotes: 144
Views: 207184
Reputation: 1755
I am surprised no one had mentioned magic_enum before. It provides stream operators and prints the name string instead of the integer value:
#include <magic_enum/magic_enum_iostream.hpp>
#include <iostream>
using magic_enum::iostream_operators::operator<<; // out-of-the-box ostream operators for enums..
int main()
{
enum class Color { RED, GREEN, BLUE};
Color c = Color::BLUE;
std::cout << c << '\n';
}
Note: The author requested a solution for C++11, but magic_enum is C++17. Nevertheless, I think this answer is valid in 2024 :)
Upvotes: 1
Reputation: 25
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);
}
Upvotes: 1
Reputation: 47619
Since c++23 there is
std::to_underlying
which does the same thing as in all the other answer but it's in std
Upvotes: 3
Reputation: 305
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;
Upvotes: -2
Reputation: 12253
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);
}
Upvotes: 3
Reputation: 21728
To write simpler,
enum class Color
{
Red = 1,
Green = 11,
Blue = 111
};
int value = static_cast<int>(Color::Blue); // 111
Upvotes: 23
Reputation: 555
(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 sizestatic_assert
+is_enum
: to 'ensure' compile-time that the function does sth. with enumerations only, as suggestedBy 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);
}
Upvotes: 10
Reputation: 9602
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;
}
Upvotes: 25
Reputation: 55887
#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;
}
Upvotes: 51
Reputation: 355019
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;
Upvotes: 183