Enumerasi (C++)

Enumerasi adalah jenis yang ditentukan pengguna yang terdiri dari sekumpulan konstanta integral bernama yang dikenal sebagai enumerator.

Catatan

Artikel ini membahas jenis Bahasa enum C++ Standar ISO dan jenis cakupan (atau sangat diketik) enum class yang diperkenalkan dalam C++11. Untuk informasi tentang jenis atau private enum class di C++/CLI dan C++/CX, lihat enum class (C++/CLI dan C++/CX).public enum class

Sintaks

enum-name:
identifier

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

enum-head:
enum-keyattribute-specifier-seqoptenum-head-nameoptenum-baseopt

enum-head-name:
nested-name-specifieroptidentifier

opaque-enum-declaration:
enum-keyattribute-specifier-seqoptenum-head-nameenum-baseopt;

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

Penggunaan

// 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

Parameter

identifier
Nama jenis yang diberikan ke enumerasi.

type
Jenis enumerator yang mendasar; semua enumerator memiliki jenis yang mendasar yang sama. Mungkin jenis integral apa pun.

enum-list
Daftar enumerator yang dipisahkan koma dalam enumerasi. Setiap enumerator atau nama variabel dalam cakupan harus unik. Namun, nilai dapat diduplikasi. Dalam enum yang tidak terlingkup, cakupannya adalah cakupan di sekitarnya; dalam enum terlingkup, cakupannya adalah itu enum-list sendiri. Dalam enum terlingkup, daftar mungkin kosong, yang berlaku mendefinisikan jenis integral baru.

class
Dengan menggunakan kata kunci ini dalam deklarasi, Anda menentukan enum dilingkup, dan identifier harus disediakan. Anda juga dapat menggunakan struct kata kunci sebagai ganti class, karena kata kunci tersebut setara secara semantik dalam konteks ini.

Cakupan enumerator

Enumerasi menyediakan konteks untuk menjelaskan rentang nilai yang direpresentasikan sebagai konstanta bernama. Konstanta bernama ini juga disebut enumerator. Dalam jenis C dan C++ enum asli, enumerator yang tidak memenuhi syarat terlihat di seluruh cakupan tempat enum dideklarasikan. Dalam enum terlingkup, nama enumerator harus memenuhi syarat dengan enum nama jenis. Contoh berikut menunjukkan perbedaan dasar ini antara dua jenis 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
        { /*...*/
        }
    }
}

Setiap nama dalam enumerasi diberi nilai integral yang sesuai dengan tempatnya dalam urutan nilai dalam enumerasi. Secara default, nilai pertama ditetapkan 0, yang berikutnya ditetapkan 1, dan seterusnya, tetapi Anda dapat secara eksplisit mengatur nilai enumerator, seperti yang ditunjukkan di sini:

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

Enumerator Diamonds diberi nilai 1. Enumerator berikutnya, jika mereka tidak diberi nilai eksplisit, terima nilai enumerator sebelumnya ditambah satu. Dalam contoh sebelumnya, Hearts akan memiliki nilai 2, Clubs akan memiliki 3, dan sebagainya.

Setiap enumerator diperlakukan sebagai konstanta dan harus memiliki nama unik dalam cakupan di mana enum didefinisikan (untuk enum yang tidak terlingkup) atau di dalamnya enum sendiri (untuk enum cakupan). Nilai yang diberikan untuk nama tidak harus unik. Misalnya, pertimbangkan deklarasi enum Suityang tidak terlingkup ini:

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

DiamondsNilai , , HeartsClubs, dan Spades masing-masing adalah 5, 6, 4, dan 5. Perhatikan bahwa 5 digunakan lebih dari sekali; itu diizinkan meskipun mungkin tidak dimaksudkan. Aturan ini sama untuk enum terlingkup.

Aturan transmisi

Konstanta enum yang tidak terlingkup dapat dikonversi secara implisit ke int, tetapi int tidak pernah secara implisit dapat dikonversi ke nilai enum. Contoh berikut menunjukkan apa yang terjadi jika Anda mencoba menetapkan hand nilai yang bukan :Suit

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

Transmisi diperlukan untuk mengonversi int ke enumerator terlingkup atau tidak terlingkup. Namun, Anda dapat mempromosikan enumerator yang tidak terlingkup ke nilai bilangan bulat tanpa transmisi.

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

Menggunakan konversi implisit dengan cara ini dapat menyebabkan efek samping yang tidak diinginkan. Untuk membantu menghilangkan kesalahan pemrograman yang terkait dengan enum yang tidak terlingkup, nilai enum terlingkup sangat di ketik. Enumerator terlingkup harus memenuhi syarat dengan nama jenis enum (pengidentifikasi) dan tidak dapat dikonversi secara implisit, seperti yang ditunjukkan dalam contoh berikut:

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

Perhatikan bahwa baris hand = account_num; masih menyebabkan kesalahan yang terjadi dengan enum yang tidak terlingkup, seperti yang ditunjukkan sebelumnya. Ini diperbolehkan dengan pemeran eksplisit. Namun, dengan enum terlingkup, konversi yang dicoba dalam pernyataan berikutnya, account_num = Suit::Hearts;, tidak lagi diizinkan tanpa pemeran eksplisit.

Enum tanpa enumerator

Visual Studio 2017 versi 15.3 dan yang lebih baru (Tersedia dengan /std:c++17 dan yang lebih baru): Dengan mendefinisikan enum (reguler atau tercakup) dengan jenis yang mendasar eksplisit dan tidak ada enumerator, Anda dapat memperkenalkan jenis integral baru yang tidak memiliki konversi implisit ke jenis lain. Dengan menggunakan jenis ini alih-alih jenis dasar bawaannya, Anda dapat menghilangkan potensi kesalahan halus yang disebabkan oleh konversi implisit yang tidak disengaja.

enum class byte : unsigned char { };

Jenis baru adalah salinan yang tepat dari jenis yang mendasar, dan oleh karena itu memiliki konvensi panggilan yang sama, yang berarti dapat digunakan di seluruh ABI tanpa penalti performa. Tidak ada transmisi yang diperlukan ketika variabel jenis diinisialisasi dengan menggunakan inisialisasi daftar langsung. Contoh berikut menunjukkan cara menginisialisasi enum tanpa enumerator dalam berbagai konteks:

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

Baca juga

Deklarasi Enumerasi C
Kata kunci