C++11中enumclass的使⽤
本⽂链接:
枚举类型(enumeration)使我们可以将⼀组整型常量组织在⼀起。和类⼀样,每个枚举类型定义了⼀种新的类型。枚举属于字⾯值常量类型。
C++包含两种枚举:限定作⽤域的和不限定作⽤域的。这⾥主要介绍限定作⽤域的。不限定作⽤域的使⽤可以参考:。
C++11新标准引⼊了限定作⽤域的枚举类型(scoped enumeration)。定义限定作⽤域的枚举类型的⼀般形式是:⾸先是关键字enum class(或者等价地使⽤enum struct),随后是枚举类型名字以及⽤花括号括起来的以逗号分隔的枚举成员(enumerator)列表,最后是⼀个分号。
枚举作⽤域(enumeration scope)是指枚举类型的成员的名字的作⽤域,起⾃其声明之处,终⽌枚举定义结束之处。C语⾔规定,枚举类型的成员(enumerator)的可见范围被提升⾄该枚举类型所在的作⽤域内。这被认为有可能污染了外部的作⽤域,为此,C++11引⼊了枚举类(enum class)解决此问题。
定义不限定作⽤域的枚举类型(unscoped enumeration)时省略掉关键字class(或struct),枚举类型的名字是可选的。
如果enum是未命名的,则我们只能在定义该enum时定义它的对象。和类的定义类似,我们需要在enum定义的右侧花括号和最后的分号之间提供逗号分隔的声明列表。
枚举成员:在限定作⽤域的枚举类型中,枚举成员的名字遵循常规的作⽤域准则,并且在枚举类型的作⽤域外是不可访问的。与之相反,在不限定作⽤域的枚举类型中,枚举成员的作⽤域与枚举类型本⾝的作⽤域相同。
默认情况下,枚举值从0开始,依次加1.不过我们也能为⼀个或⼏个枚举成员指定专门的值。枚举值不⼀定唯⼀。如果我们没有显⽰地提供初始值,则当前枚举成员的值等于之前枚举成员的值加1.枚举成员是const,因此在初始化枚举成员时提供的初始值必须是常量表达式。也就是说,每个枚举成员本⾝就是⼀条常量表达式,我们可以在任何需要常量表达式的地⽅使⽤枚举成员。类似的,我们也可以将⼀个enum作为switch语句的表达式,⽽将枚举值作为case标签。出于同样的原因,我们还能将枚举类型作为⼀个⾮类型模板形参使⽤;或者在类的定义中初始化枚举类型的静态数据成员。
和类⼀样,枚举也定义新的类型:只要enum有名字,我们就能定义并初始化该类型的成员。要想初始化enum对象或者为enum对象赋值,必须使⽤该类型的⼀个枚举成员或者该类型的另⼀个对象。
⼀个不限定作⽤域的枚举类型的对象或枚举成员⾃动地转换成整型。因此,我们可以在任何需要整型值的地⽅使⽤它们。⽽限定作⽤域的枚举类型不会进⾏隐式转换。
指定enum的⼤⼩:尽管每个enum都定义了唯⼀的类型,但实际上enum是由某种整数类型表⽰的。在C++11标准中,我们可以在enum的名字后加上冒号以及我们想在该enum中使⽤的类型。如果我们没有指定enum的潜在类型,则默认情况下限定作⽤域的enum成员类型是int。对于不限定作⽤域的枚举类型来说,其枚举成员不存在默认类型,我们只知道成员的潜在类型⾜够⼤,肯定能够容纳枚举值。如果我们指定了枚举成员的潜在类型(包括对限定作⽤域的enum的隐式指定),则⼀旦某个枚举成员的值超出了该类型所能容纳的范围,将引发程序错误。
指定enum潜在类型的能⼒使得我们可以控制不同实现环境中使⽤的类型,我们将可以确保在⼀种实现环境中编译通过的程序所⽣成的代码与其他实现环境中⽣成的代码⼀致。
枚举类型的前置声明:在C++11新标准中,我们可以提前声明enum。enum的前置声明(⽆论隐式地还是显⽰地)必须指定其成员的⼤⼩。不限定作⽤域的,必须指定成员类型。限定作⽤域的枚举类型可以使⽤默认成员类型int。因为不限定作⽤域的enum未指定成员的默认⼤⼩,因此每个声明必须指定成员的⼤⼩。对于限定作⽤域的enum来说,我们可以不指定其成员的⼤⼩,这个值被隐式地定义成int。和其它声明语⾔⼀样,enum的声明和定义必须匹配,这意味着在该enum的所有声明和定义中成员的⼤⼩必须⼀致。⽽且,我们不能在同⼀个上下⽂中先声明⼀个不限定作⽤域的enum名字,然后再声明⼀个同名的限定作⽤域的enum。
形参匹配与枚举类型:要想初始化⼀个enum对象,必须使⽤该enum类型的另⼀个对象或者它的⼀个枚举成员。因此,即使某个整型值恰好与枚举成员的值相等,它也不能作为函数的enum实参使⽤。不限定作⽤域的枚举类型,潜在类型因机器⽽异。尽管我们不能直接将整型值传给enum实参,但是可以将⼀个不限定作⽤域的枚举类型的对象或枚举成员传给整型形参。此时,enum的值提升成int或更⼤的整型,实际提升的结果由枚举类型的潜在类型决定。
The enum classes("new enums", "strong enums") address three problems with traditional C++ enumerations:
1. conventional enums implicitly convert to int, causing errors when someone does not want an enumeration to act as an integer.
2. conventional enums export their enumerators to the surrounding scope, causing name clashes.
3. the underlying type of an enum cannot be specified, causing confusion,compatibility problems, and makes forward declaration impossible.
The new enums are "enum class" because they combine aspects of traditional enumerations (names values) with aspects of classes (scoped members and absense of conversions).
C++ has two kinds of enum: enum classes,Plain enums.
下⾯是从其他⽂章中copy的测试代码,详细内容介绍可以参考对应的reference:
#include "enum_class.hpp"
#include <iostream>
namespace enum_class_ {
typedef short int16_t;
////////////////////////////////////////////////////////////////////
// reference: en.cppreference/w/cpp/language/enum
// enum that takes 16 bits
enum smallenum : int16_t {
a,
b,
c
};
// color may be red (value 0), yellow (value 1), green (value 20), or blue (value 21)
enum color {
red,
yellow,
green = 20,
blue
};
// altitude may be altitude::high or altitude::low
enum class altitude : char {
high = 'h',
enum类型如何使用low = 'l', // C++11 allows the extra comma
};
// the constant d is 0, the constant e is 1, the constant f is 3
enum {
d,
e,
f = e + 2
};
//enumeration types (both scoped and unscoped) can have overloaded operators
std::ostream& operator << (std::ostream& os, color c)
{
switch (c) {
case red: os << "red";    break;
case yellow: os << "yellow"; break;
case green: os << "green";  break;
case blue: os << "blue";  break;
default: os.setstate(std::ios_base::failbit);
}
return os;
}
std::ostream& operator << (std::ostream& os, altitude al)
{
return os << static_cast<char>(al);
}
int test_enum_class_1()
{
color col = red;
altitude a;
a = altitude::low;
std::cout << "col = " << col << '\n'
<< "a = " << a << '\n'
<< "f = " << f << '\n';
return 0;
}
////////////////////////////////////////////////////////////////////////
// reference: stackoverflow/questions/18335861/why-is-enum-class-preferred-over-plain-enum
// C++ has two kinds of enum: enum classes, Plain enums
enum Color { red1, green1, blue1 };                    // plain enum
enum Card { red_card, green_card, yellow_card };    // another plain enum
enum class Animal { dog, deer, cat, bird, human };  // enum class
enum class Mammal { kangaroo, deer, human };        // another enum class
int test_enum_class_2()
{
// examples of bad use of plain enums:
Color color = Color::red1;
Card card = Card::green_card;
int num = color;    // no problem
if (color == Card::red_card) // no problem (bad)
std::cout << "bad" << std::endl;
if (card == Color::green1)  // no problem (bad)
std::cout << "bad" << std::endl;
// examples of good use of enum classes (safe)
Animal a = Animal::deer;
Mammal m = Mammal::deer;
//int num2 = a;  // error
//if (m == a)    // error (good)
// std::cout << "bad" << std::endl;
//if (a == Mammal::deer) // error (good)
// std::cout << "bad" << std::endl;
return 0;
}
////////////////////////////////////////////////////////
// reference: www.learncpp/cpp-tutorial/4-5a-enum-classes/
int test_enum_class_3()
{
enum class Color { // "enum class" defines this as an scoped enumeration instead of a standard enumeration
RED, // RED is inside the scope of Color
BLUE
};
enum class Fruit {
BANANA, // BANANA is inside the scope of Fruit
APPLE
};
Color color = Color::RED; // note: RED is not directly accessible any more, we have to use Color::RED
Fruit fruit = Fruit::BANANA; // note: BANANA is not directly accessible any more, we have to use Fruit::BANANA  //if (color == fruit) // compile error here, as the compiler doesn't know how to compare different types Color and Fruit  // std::cout << "color and fruit are equal\n";
//else
// std::cout << "color and fruit are not equal\n";
if (color == Color::RED) // this is okay
std::cout << "The color is red!\n";
else if (color == Color::BLUE)
std::cout << "The color is blue!\n";
//std::cout << color; // won't work, because there's no implicit conversion to int
color = Color::BLUE;
std::cout << static_cast<int>(color) << std::endl; // will print 1
return 0;
}
} // namespace enum_class_
GitHub:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。