Подтвердить что ты не робот

Как я могу вывести значение класса enum в С++ 11

Как я могу вывести значение enum class в С++ 11? В С++ 03 это так:

#include <iostream>

using namespace std;

enum A {
  a = 1,
  b = 69,
  c= 666
};

int main () {
  A a = A::c;
  cout << a << endl;
}

в С++ 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

4b9b3361

Ответ 1

В отличие от перечисления с незапланированным охватом, перечисление с областью не косвенно конвертируется в его целочисленное значение. Вам нужно явно преобразовать его в целое число с помощью cast:

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;

Ответ 2

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

Ответ 3

Возможно, что ваш второй пример (т.е. Тот, что использует перечисление с областью видимости) работает с использованием того же синтаксиса, что и перечисления с незаданной областью. Кроме того, решение является общим и будет работать для всех перечислений с областью, в отличие от написания кода для каждого перечисления с областью (как показано в ответе, предоставленном @ForEveR).

Решение состоит в том, чтобы написать универсальную функцию operator<< которая будет работать для любого enum-объекта. Решение использует 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;
}

Ответ 4

(Мне еще не разрешено прокомментировать.) Я бы предложил следующие улучшения в уже отличном ответе Джеймса Макнеллиса:

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, как я предложил здесь: Как использовать перечисления как флаги в С++?


Еще один (лучший) вкус этого без 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);
}

Ответ 5

Проще написать,

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

int value = static_cast<int>(Color::Blue); // 111

Ответ 6

Следующее работает для меня в С++ 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);
}

Ответ 7

Вы можете сделать что-то вроде этого:

//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;