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