Как я могу вывести значение класса enum в C++11
как я могу вывести значение enum class
в C++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
4 ответа:
В отличие от перечисления без области, перечисление с областью не является имплицитно конвертируемых в его целочисленное значение. Вам нужно явно преобразовать его в целое число, используя гипс:
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;
#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).
решение состоит в том, чтобы написать общий
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; }
(Я пока не могу комментировать.) Я бы предложил следующие улучшения без ответа Джеймс 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); }
С
constexpr
: позволяет мне использовать значение перечисления в качестве размера массива времени компиляцииstatic_assert
+is_enum
: чтобы "гарантировать" время компиляции, что функция выполняет sth. только с перечислениями, как было предложенокстати, я спрашиваю себя: Почему я должен когда-либо использовать
enum class
когда я хотели бы присвоить числовые значения моим членам перечисления?! Учитывая усилия по преобразованию.возможно, тогда я вернусь к обычным
enum
как я предлагал здесь: как использовать перечисления в качестве флагов в C++?
еще один (лучший) аромат без static_assert, основанный на предложении @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); }