前言
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 Color
、enum 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
标准流的问题,为了解决这个问题,提供了三种解决方案。
- 第一种解决方案是通过强制类型转换将枚举类转换为底层的 int 类型,然后输出 int 值。
- 第二种解决方案是通过重载
operator<<
操作符,将枚举类转换为底层类型后输出。 - 第三种解决方案是使用 C++的 SFINAE 技术,通过泛型支持任何枚举类,并将枚举类转换为底层类型后输出。
这些解决方案都可以解决无法直接输出枚举类的问题,并提供了不同的选择和灵活性。
How can I output the value of an enum class in C++11 - Stack Overflow