如何在 C + + 11中输出枚举类的值

如何在 C + + 11中输出 enum class的值? 在 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

157895 次浏览

与无作用域枚举不同,有作用域枚举不能转换为其整数值。您需要使用强制转换将 明确地转换为整数:

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

(我还不能发表评论)我建议对詹姆斯 · 麦克内利斯(James 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: 按照建议,“确保”编译时该函数仅使用枚举进行某些操作

顺便问一下我自己: 当我想给我的枚举成员分配数值时,为什么我要使用 enum class? !考虑到转换的努力。

也许我会回到普通的 enum,就像我在这里建议的那样: 如何在 C + + 中使用枚举作为标志?


根据@TobySpeight 的建议,还有一种(更好的)没有 static _ asserit 的风格:

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

可以使用与非作用域枚举相同的语法使第二个示例(即使用作用域枚举的示例)工作。此外,该解决方案是通用的,并且适用于所有作用域枚举,而不是为每个作用域枚举编写代码(如 @ 永远提供的 回答所示)。

解决方案是编写一个通用的 operator<<函数,该函数适用于任何范围内的枚举。该解决方案通过 std::enable_if使用 SFINAE,如下所示。

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

为了写得更简单,

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


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

下面的内容在 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);
}

你可以这样做:

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

因为 c + + 23有

std::to_underlying 和其他答案一样,但是是标准答案

在 James McNellis 的精彩回答的基础上,如果你的编译器支持 概念和约束(C + + 20中引入的) ,它可以用来为函数模板引入额外的编译时健全性(比如,更清楚地指出任何不正确的用法) ,方式如下:

template<typename E>
concept EnumType = std::is_enum_v<E>;


template <EnumType E>
constexpr std::underlying_type_t<E> enumUnderlyingType(E const underlying_type)
{
return static_cast<std::underlying_type_t<E>>(underlying_type);
}