Skip to content

Enum

cppreference Enumeration declaration

An enumeration is a distinct type whose value is restricted to a range of values (see below for details), which may include several explicitly named constants ("enumerators"). The values of the constants are values of an integral type known as the underlying type of the enumeration.

NOTE:

enumerator is named constant

本节的标题的含义是: enumerator 本质上是constant;这就决定了enum的如下属性:

属性 参见
可以用于static context C-and-C++\Compile-time-and-run-time
value category是prvalue C++\Language-reference\Expressions\Value-categories

关于constant,参见C++\Language-reference\Expressions\Constant-expressions

enumerator is value and is not object

enumerator 是 value,而不是 object,这是一个非常重要的事实,这决定了enumerator的value category是prvalue。

There are two distinct kinds of enumerations:

1) unscoped enumeration (declared with the enum-key enum)

1) scoped enumeration (declared with the enum-key enum class or enum struct). (since C++11)

Underlying type

NOTE: 原文并没有Underlying type标题,我添加的目的是对underlying type进行统一描述。

*underlying type*的概念是非常重要的,在C++11之前,C++语言并没有对enum的underlying type进行统一,也没有提供syntax来供programmer对它进行指定,C++11则解决了这个问题,它提供了syntax来供programmer对underlying type进行指定

Specify underlying type

syntax 注解
enum-key attr(optional) enum-name enum-base; colon (:), followed by a type-specifier-seq that names an integral type (if it is cv-qualified, qualifications are ignored) that will serve as the fixed underlying type for this enumeration type
#include <cstdint>

// enum that takes 16 bits
enum smallenum: std::int16_t
{
    a,
    b,
    c
};

// altitude may be altitude::high or altitude::low
enum class altitude: char
{ 
     high='h',
     low='l', // C++11 allows the extra comma
}; 

Query underlying type

如何获取它呢?参见:std::underlying_type

TODO

1) stackoverflow What is the underlying type of a c++ enum?

Output the value of enum class

在 stackoverflow How can I output the value of an enum class in C++11 的回答中给出的code,值的借鉴:

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

Unscoped enumeration

Scoped enumerations

Enum Classes VS Enum

https://www.geeksforgeeks.org/enum-classes-in-c-and-their-advantage-over-enum-datatype/

Simulate scoped enumeration before C++11

如何在C++11之前的版本中模拟scoped enumeration ?

stackoverflow How to use enums in C++

A

This code is wrong:

enum Days { Saturday,Sunday,Tuesday,Wednesday,Thursday,Friday};
Days day = Days.Saturday;
if(day == Days.Saturday)

Because Days is not a scope, nor object. It is a type. And Types themselves don't have members. What you wrote is the equivalent to std::string.clear. std::string is a type, so you can't use .on it. You use . on an instance of a class.

Unfortunately, enums are magical and so the analogy stops there. Because with a class, you can do std::string::clear to get a pointer to the member function, but in C++03, Days::Sunday is invalid. (Which is sad). This is becauseC++ is (somewhat) backwards compatable with C, and C had no namespaces, so enumerations had to be in the global namespace. So the syntax is simply:

enum Days { Saturday,Sunday,Tuesday,Wednesday,Thursday,Friday};
Days day = Saturday;
if(day == Saturday)

Fortunately, Mike Seymour observes that this has been addressed in C++11. Change enum to enum class and it gets its own scope; so Days::Sunday is not only valid, but is the only way to access Sunday. Happy days!

A

You can use a trick to use scopes as you wish, just declare enum in such way:

struct Days 
{
   enum type
   {
      Saturday,Sunday,Tuesday,Wednesday,Thursday,Friday
   };
};

Days::type day = Days::Saturday;
if (day == Days::Saturday)

Enum and string

为enum的每个可选值指定一个name(string),这是我们的一种常见需求,那如何来实现呢?这是本节讨论的问题。下面讨论了各种实现方式:

1) switch-case

使用switch-case来实现,在cppreference Enumeration declarationExample中给出的例子非常好。

2) map + TMP

这是我在阅读stackoverflow Specialization of template in different namespaceC++\Language-reference\Template\Specialization\Specialization-of-template-in-different-namespace.md中收录了这篇文章)时,发现的一种实现,下面是对原文的代码的整理,将它放到了同一个文件中,并且修正了compiler error:

#include <iostream>
#include <map>
#include <cstring>
namespace MyLib
{

#define DECLARE_ENUM( type ) template<> std::map<const char*, type>  \
            MyLib::Enum<type>::mMap = std::map<const char*, type>(); \
            template<> MyLib::Enum<type>::Enum (void)

template<typename Type> class Enum
{
public:
    Enum(void);
    static int Size(void)
    { /* ... */
        return mMap.size();
    }

private:
    static std::map<const char*, Type> mMap;
};

}

enum MyEnum
{
    value1, value2, value3,
};

namespace MyLib
{
DECLARE_ENUM (MyEnum)
{
    mMap["value1"] = value1;
    mMap["value2"] = value2;
    mMap["value3"] = value3;
}
}
void SomeFunc(void)
{
    std::cout << MyLib::Enum<MyEnum>::Size() << std::endl;
}
// 触发构造
static MyLib::Enum<MyEnum> g_E;

int main()
{

    SomeFunc();
}
// g++ --std=c++11 test.cpp

上述代码的实现是非常值得借鉴的,每个enum都有一个对应的Enum类,这个类保存了enum的一个mapping: name to value。

输出为:

3

3) array + enum as index

保存enum的name,使用array的方式,不使用map,这是我在阅读 cppreference Array initialization # Example 时看到的:

#include <iostream>
int main(void)
{

    // Character names can be associated with enumeration constants
    // using arrays with designators:
    enum
    {
        RED, GREEN, BLUE
    };
    const char *nm[] = { [RED] = "red", [GREEN] = "green", [BLUE] = "blue", };
    std::cout << sizeof(nm) / sizeof(nm[0]) << std::endl;
}
g++ -g test.cpp

输出为:

3

TODO

stackoverflow enum to string in modern C++11 / C++14 / C++17 and future C++20

stackoverflow enum class of type string in C++

github magic_enum

enum in TMP

1、我记得在TMP中,有多处是使用到了enum的,这些都整理到了 Dispatch-based-on-constant

2、将此称为 Enum dispatch

TODO enum and callback function

这其实是要实现polymorphism。

https://www.codeproject.com/Articles/10006/How-to-create-an-enum-and-callback-function

https://www.drdobbs.com/callback-enumeration-apis-the-input-ite/184401766