How can I infer the value of the enum class in C ++ 11

How can I infer the enum class value in C ++ 11? In C ++ 03, it is 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 does not 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 by Ideone.com

+82
c ++ enums c ++ 11 enum-class
Jul 10 2018-12-12T00:
source share
6 answers

Unlike an enumeration with unplanned coverage, an enumeration with a region is not indirectly converted to its integer value. You need to explicitly convert it to an integer using cast:

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

You might want to encapsulate the logic in 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; 
+105
Jul 10 2018-12-12T00:
source share
 #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; } 
+37
Jul 10 2018-12-12T00:
source share

It is possible that your second example (i.e., one that uses an enumeration with a scope) works using the same syntax as an enumeration with an undefined scope. In addition, the solution is generic and will work for all enumerations with a scope, as opposed to writing code for each enumeration with a scope (as shown in the answer provided by @ForEveR ).

The solution is to write a universal operator<< function that will work for any enum object. The solution uses SFINAE via std::enable_if and looks like this.

 #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; } 
+18
Jan 29 '15 at 4:02
source share

(I am not yet allowed to comment.) I would suggest the following improvements to James McNellis's already excellent answer:

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

from

  • constexpr : allows me to use the value of an enumeration element as the size of a compile-time array
  • static_assert + is_enum : "ensure" the compilation time that the sth function executes. with listings as suggested

By the way, I ask myself: why should I ever use enum class when I would like to assign numerical values ​​to my enumeration members ?! Given the conversion effort.

Perhaps I will return to the regular enum , as I suggested here: How to use enums as flags in C ++?




Another (better) taste of this without static_assert, based on @TobySpeight's suggestion:

 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); } 
+9
Nov 07 '14 at 19:57
source share

It's easier to write

 enum class Color { Red = 1, Green = 11, Blue = 111 }; int value = static_cast<int>(Color::Blue); // 111 
+4
Jan 31 '19 at 14:41
source share

The following works 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); } 
0
Jul 20 '19 at 9:04 am
source share



All Articles