Featured image of post C++ 打印enum class枚举类

C++ 打印enum class枚举类

在 C++11中,由于枚举类(enum class)无法通过 std::cout 标准流打印,为了解决这个问题,提供了三种解决方案。

# 前言

C++11 中引入了强类型的 enum class 类型(或称为枚举类),但是有一点比较尴尬的是,std::cout 标准流不支持输出 enum class 类型。

比如以下代码:

1
2
3
4
5
6
7
8
9
#include <iostream>
 
int main()
{
    enum class Color { red, green = 20, blue };
    Color r = Color::blue;
 
    std::cout << r;
}

在编译时,会有报错,GCC 编译错误信息:

1
2
3
4
5
6
main.cpp:8:14: error: no match for 'operator<<' (operand types are 'std::ostream' {aka 'std::basic_ostream<char>'} and 'main()::Color')
    8 |     std::cout<<r;
      |     ~~~~~~~~~^~~
      |          |     |
      |          |     main()::Color
      |          std::ostream {aka std::basic_ostream<char>}

MSVC编译错误信息:

1
E0349	没有与这些操作数匹配的 "<<" 运算符

那么,如何打印 enum class 呢?

# 解决方案

# 方法一

enum class 底层类型其实是 int 类型,那么我们可以直接进行强制类型转换即可:

1
2
3
4
5
6
7
8
enum class Color { red, green = 20, blue };
Color r = Color::blue;

std::cout<< static_cast<int>(r) << std::endl;
// 或者
std::cout<< static_cast<typename std::underlying_type<Color>::type>(r) << std::endl; 

// 输出:21

# 方法二

每次都要强制类型转换,太麻烦了,还有更方便点的办法吗?当然有!可以通过重载 operator<< 操作符实现:

1
2
3
4
5
std::ostream& operator << (std::ostream& os, const Color& obj)
{
   os << static_cast<std::underlying_type<Color>::type>(obj);
   return os;
}

这样就可以直接使用 std::cout 打印,而不需要先强制转换一次。

1
std::cout<< r << std::endl;

# 方法三

如果我有多个 enum class 呢,比如 enum Colorenum Fruit,那我岂不是都要重载 operator<< 操作符一次?所以这里使用 C++黑魔法 SFINAE 从而泛型支持任何枚举类,而不限定于某特定的枚举类:

1
2
3
4
5
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);
}

例子:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <type_traits>

// Scoped enum
enum class Color
{
    Red,
    Green,
    Blue
};

// Unscoped enum
enum Orientation
{
    Horizontal,
    Vertical
};

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";
    return 0;
}

缺陷

对于命名空间里的枚举类不能打印,即以下E无法识别:

1
2
3
namespace nn{
enum class E {}
}

# 总结

在 C++11中,由于枚举类(enum class)无法直接输出到 std::cout 标准流的问题,为了解决这个问题,提供了三种解决方案。

  1. 第一种解决方案是通过强制类型转换将枚举类转换为底层的 int 类型,然后输出 int 值。
  2. 第二种解决方案是通过重载 operator<< 操作符,将枚举类转换为底层类型后输出。
  3. 第三种解决方案是使用 C++的 SFINAE 技术,通过泛型支持任何枚举类,并将枚举类转换为底层类型后输出。

这些解决方案都可以解决无法直接输出枚举类的问题,并提供了不同的选择和灵活性。

How can I output the value of an enum class in C++11 - Stack Overflow

Licensed under CC BY-NC-SA 4.0