#include<iostream>intmain(){enumColor{red,blue,};enumFruit{banana,apple,};Colorcolor{red};Fruitfruit{banana};if(color==fruit)// 编译器会将 color 和 fruit 当做整型进行比较std::cout<<"color and fruit are equal\n";// 并认为它们相等elsestd::cout<<"color and fruit are not equal\n";return0;}
打印:
1
color and fruit are equal
当 color 和 fruit 进行比较时,编译器会首先判断它是否知道如何比较Color 和 Fruit。它并不知道。然后,它就会尝试将 Color 或 Fruit 转换为整型并继续查看是有匹配的比较方法。最终,编译器会将二者都转换为整型并进行比较。因为 color 和 fruit 的枚举值都转换为0,所以它们是相等的。
这显然不合理,因为 color 和 fruit 来自两个不同的枚举类型,它们本来是不具有可比性的。对于一般的枚举来说,我们并没有简单的办法放置此类事情发生。
#include<iostream>intmain(){enumclassColor// "enum class" 定义了有作用域枚举类型{red,// red 是 Color 作用域的成员blue,};enumclassFruit{banana,// banana 是 Fruit 作用域的成员apple,};Colorcolor{Color::red};// 注意: red 不能够被直接访问,必须使用 Color::redFruitfruit{Fruit::banana};// note: banana 不能够被直接访问, 必须使用 Fruit::bananaif(color==fruit)// 编译错误:编译器不知道如何比较 Color 和 Fruitstd::cout<<"color and fruit are equal\n";elsestd::cout<<"color and fruit are not equal\n";return0;}
编译器会报告程序的第19行存在错误,因为有作用域枚举不能够被转换为任何可比较的其他类型。
题外话
class 关键字 (以及static关键字)是 C++ 中最被“滥用”的关键字,它在不同语境下具有不同的含义。尽管有作用域枚举类型使用了 class 关键字,但是它们并不是类类型(类类型包括结构体、类和联合体)。
#include<iostream>intmain(){enumclassColor// "enum class" defines this as a scoped enum rather than an unscoped enum{red,// red is considered part of Color's scope regionblue,};std::cout<<red<<'\n';// compile error: red not defined in this scope regionstd::cout<<Color::red<<'\n';// compile error: std::cout doesn't know how to print this (will not implicitly convert to int)Colorcolor{Color::blue};// okayreturn0;}
#include<iostream>intmain(){enumclassColor{red,blue,};Colorshirt{Color::red};if(shirt==Color::red)// Color 和 Color 的比较是可以的std::cout<<"The shirt is red!\n";elseif(shirt==Color::blue)std::cout<<"The shirt is blue!\n";return0;}
#include<iostream>intmain(){enumclassColor{red,blue,};Colorcolor{Color::blue};std::cout<<color<<'\n';// won't work, because there's no implicit conversion to intstd::cout<<static_cast<int>(color)<<'\n';// will print 1return0;}
#include<iostream>enumclassPet{cat,// assigned 0dog,// assigned 1pig,// assigned 2whale,// assigned 3};intmain(){std::cout<<"Enter a pet (0=cat, 1=dog, 2=pig, 3=whale): ";intinput{};std::cin>>input;// input an integerPetpet{static_cast<Pet>(input)};// static_cast our integer to a Petreturn0;}
#include<iostream>enumclassAnimals{chicken,// 0dog,// 1cat,// 2elephant,// 3duck,// 4snake,// 5maxAnimals,};// Overload the unary + operator to convert Animals to the underlying type// adapted from https://stackoverflow.com/a/42198760, thanks to Pixelchemist for the ideaconstexprautooperator+(Animalsa)noexcept{returnstatic_cast<std::underlying_type_t<Animals>>(a);}intmain(){std::cout<<+Animals::elephant<<'\n';// convert Animals::elephant to an integer using unary operator+return0;}
打印:
1
3
此方法可避免不经意地隐式转换,同时还提供了一种方便地显示转换方法。
using enum 语句 (C++20)
C++20 引入了 using enum 语句,它可以将每个枚举作用域中的枚举值全部导入到当前作用域。当配合枚举类使用时,可以避免使用枚举类前缀访问枚举值。
#include<iostream>#include<string_view>enumclassColor{black,red,blue,};constexprstd::string_viewgetColor(Colorcolor){usingenumColor;// bring all Color enumerators into current scope (C++20)// We can now access the enumerators of Color without using a Color:: prefixswitch(color){caseblack:return"black";// note: black instead of Color::blackcasered:return"red";caseblue:return"blue";default:return"???";}}intmain(){Colorshirt{Color::blue};std::cout<<"Your shirt is "<<getColor(shirt)<<'\n';return0;}
在上面的例子中, Color 是一个枚举类,所以我们通常需要使用完全限定名来访问其枚举值 (例如 Color::blue)。但是,在 getColor() 函数中, 由于我们使用了 using enum Color;,因此可以省略 Color:: 前缀直接访问枚举值。