列舉 (C++)

列舉是由一組稱為 列舉值之具名整數常數所組成的使用者定義型別

注意

本文涵蓋 ISO 標準 C++ 語言 enum 類型和 C++11 中引進的範圍(或強型別) enum class 類型。 如需 C++/CLI 和 C++/CX 中 或 private enum class 類型的相關資訊 public enum class ,請參閱 enum class (C++/CLI 和 C++/CX)。

語法

enum-name
identifier

enum-specifier
enum-head{enumerator-listopt}
enum-head { enumerator-list , }

enum-head
enum-keyattribute-specifier-seqopt opt opt enum-baseenum-head-name

enum-head-name
nested-name-specifieroptidentifier

opaque-enum-declaration
enum-keyattribute-specifier-seqopt opt enum-head-nameenum-base;

enum-key
enum
enum class
enum struct

enum-base
: type-specifier-seq

enumerator-list
enumerator-definition
enumerator-list , enumerator-definition

enumerator-definition
enumerator
enumerator = constant-expression

enumerator
identifierattribute-specifier-seqopt

使用方式

// unscoped enum:
// enum [identifier] [: type] {enum-list};

// scoped enum:
// enum [class|struct] [identifier] [: type] {enum-list};

// Forward declaration of enumerations  (C++11):
enum A : int;          // non-scoped enum must have type specified
enum class B;          // scoped enum defaults to int but ...
enum class C : short;  // ... may have any integral underlying type

參數

identifier
提供給列舉的類型名稱。

type
列舉值的基礎類型,所有列舉值都有相同的基礎類型。 可以是任何整數類資料類型。

enum-list
在列舉中,列舉值的逗號分隔清單。 範圍內的每個列舉值或變數名稱都必須是唯一的。 不過,值可以重複。 在未範圍列舉中,範圍是周圍的範圍;在範圍列舉中,範圍是 enum-list 本身。 在範圍列舉中,清單可能是空的,實際上會定義新的整數類型。

class
藉由在宣告中使用這個關鍵字,您可以指定列舉的範圍,而且 identifier 必須提供 。 您也可以使用 struct 關鍵字取代 class ,因為它們在此內容中語意上相等。

列舉值範圍

列舉提供內容來描述以具名常數表示的值範圍。 這些具名常數也稱為 列舉值 。 在原始 C 和 C++ enum 類型中,宣告 的整個範圍 enum 都會顯示不合格的列舉值。 在範圍列舉中,列舉值名稱必須以 enum 類型名稱限定。 下列範例示範這兩種列舉之間的這項基本差異:

namespace CardGame_Scoped
{
    enum class Suit { Diamonds, Hearts, Clubs, Spades };

    void PlayCard(Suit suit)
    {
        if (suit == Suit::Clubs) // Enumerator must be qualified by enum type
        { /*...*/}
    }
}

namespace CardGame_NonScoped
{
    enum Suit { Diamonds, Hearts, Clubs, Spades };

    void PlayCard(Suit suit)
    {
        if (suit == Clubs) // Enumerator is visible without qualification
        { /*...*/
        }
    }
}

列舉中的每個名稱被指派整數值,這個值對應於它在列舉值順序中的位置。 根據預設,第一個指派的值是 0,下一個指派的是 1,依此類推,不過,您可以明確設定列舉程式的值,如下所示:

enum Suit { Diamonds = 1, Hearts, Clubs, Spades };

指派給列舉值 Diamonds 的值為 1。 如果後續列舉值未指定明確值,則會收到前一個列舉值加上一個列舉值。 在上述範例中,Hearts 會有值 2,而 Clubs 會有 3,依此類推。

每個列舉值都會被視為常數,而且在定義 的範圍 enum 中必須有唯一的名稱(針對未範圍列舉),或本身內 enum 的唯一名稱(針對範圍列舉)。 提供給名稱的值不一定是唯一的。 例如,請考慮這個未範圍列舉 Suit 的宣告:

enum Suit { Diamonds = 5, Hearts, Clubs = 4, Spades };

HeartsClubsSpades 的值 Diamonds 分別為 5、6、4 和 5。 請注意,5 已多次使用;即使它可能不適合,還是允許它。 對於限定範圍列舉,這些規則都相同。

轉型規則

未範圍列舉常數可以隱含地轉換成 int ,但 int 永遠無法隱含轉換成列舉值。 下列範例顯示如果您嘗試指派 hand 不是 Suit 的值,會發生什麼情況:

int account_num = 135692;
Suit hand;
hand = account_num; // error C2440: '=' : cannot convert from 'int' to 'Suit'

轉換必須轉換成 int 範圍或未限定範圍的列舉值。 不過,您可以將無範圍列舉值升階為沒有轉換的整數值。

int account_num = Hearts; //OK if Hearts is in an unscoped enum

以這種方式使用隱含轉換,可能造成非預期的副作用。 為了協助排除與不限範圍的列舉關聯之程式設計錯誤,範圍列舉值是強類型。 範圍列舉值必須以列舉類型名稱 (identifier) 限定,且無法隱含轉換,如下列範例所示:

namespace ScopedEnumConversions
{
    enum class Suit { Diamonds, Hearts, Clubs, Spades };

    void AttemptConversions()
    {
        Suit hand;
        hand = Clubs; // error C2065: 'Clubs' : undeclared identifier
        hand = Suit::Clubs; //Correct.
        int account_num = 135692;
        hand = account_num; // error C2440: '=' : cannot convert from 'int' to 'Suit'
        hand = static_cast<Suit>(account_num); // OK, but probably a bug!!!

        account_num = Suit::Hearts; // error C2440: '=' : cannot convert from 'Suit' to 'int'
        account_num = static_cast<int>(Suit::Hearts); // OK
    }
}

請注意,程式行 hand = account_num; 仍然會導致因為不限範圍的列舉而發生的錯誤,如上所示。 允許使用明確的轉換。 不過,使用限定範圍列舉時,不再允許在沒有明確轉型的情況下,於下一個陳述式 account_num = Suit::Hearts; 中嘗試轉換。

沒有列舉值的列舉

Visual Studio 2017 15.3 版和更新版本(適用于 /std:c++17 和更新版本 ):藉由定義具有明確基礎型別和沒有列舉值的列舉(一般或範圍),您實際上可以引進沒有隱含轉換成任何其他型別的新整數型別。 藉由使用此類型,而不是其內建基礎類型,您可以消除因不小心隱含轉換所造成的細微錯誤。

enum class byte : unsigned char { };

新類型是基礎型別的確切複本,因此具有相同的呼叫慣例,這表示它可以跨 ABIS 使用,而不會造成任何效能損失。 使用直接清單初始化初始化類型變數時,不需要轉換。 下列範例示範如何在各種內容中初始化沒有列舉值的列舉:

enum class byte : unsigned char { };

enum class E : int { };
E e1{ 0 };
E e2 = E{ 0 };

struct X
{
    E e{ 0 };
    X() : e{ 0 } { }
};

E* p = new E{ 0 };

void f(E e) {};

int main()
{
    f(E{ 0 });
    byte i{ 42 };
    byte j = byte{ 42 };

    // unsigned char c = j; // C2440: 'initializing': cannot convert from 'byte' to 'unsigned char'
    return 0;
}

另請參閱

C 列舉宣告
關鍵字