Как я могу вывести значение класса 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 61

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