C ++ 'da numaralandırma nasıl kullanılır


218

Varsayalım ki enumaşağıdakine benzer:

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

Bunun bir örneğini oluşturmak enumve uygun bir değerle başlatmak istiyorum , bu yüzden:

Days day = Days.Saturday;

Şimdi değişkenimi veya örneğimi var olan bir enumdeğerle kontrol etmek istiyorum , bu yüzden yapıyorum:

if (day == Days.Saturday)
{
    std::cout << "Ok its Saturday";
}

Bu bana bir derleme hatası veriyor:

hata: '.' öğesinden önce beklenen birincil ifade. jeton

Açık olmak gerekirse, aşağıdakiler arasındaki fark nedir:

if (day == Days.Saturday) // Causes compilation error

ve

if (day == Saturday)

?

Bu ikisinin gerçekte neyi ifade ediyor, biri iyi ve biri derleme hatasına neden oluyor?


4
biliyorum, neden bana hata verdiğini bilmek istiyorum!
Rika

1
Çarşamba burada. C ++ derleyicisi için çok fazla sözdizimi hatası var. 'Enum' dan başlayarak.
Öö Tiib

1
@Hossein, Çünkü sıralamalar her iki dilde de aynı sözdizimi (ve anlambilim) değildir. Yeni bir dilde bir özellik kullanmaya çalışırken bir hata aldıktan sonra yaptığım ilk şey, söz konusu dildeki sözdizimini (veya mümkünse) aramaktır.
chris

@chris: Biliyorum, aynı şeyi yapıyorum. umarım cevabımı aldım. Ayrıca soruyu daha net olacak şekilde güncelledim. Bu arada teşekkür ederim;)
Rika

17
" bildiğim kadarıyla bu iki dilde numaralandırma bildirimi ve kullanımı aynı. " Senin sorunun var, tam orada. C #, C ++ ile aynı dil değildir . Özellikle numaralandırmalar için farklı sözdizimleri vardır.
Robᵩ

Yanıtlar:


350

Bu kod yanlış:

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

Çünkü Daysne kapsam ne de nesne. Bu bir tür. Ve Türlerin kendilerinin üyesi yoktur. Yazdığınız şey eşdeğerdir std::string.clear. std::stringbir tür, bu yüzden .üzerinde kullanamazsınız . Sen kullanmak ., bir de örneğin bir sınıfın.

Ne yazık ki, sıralamalar büyülü ve bu yüzden benzetme orada duruyor. Çünkü bir sınıfla std::string::clearüye işlevine bir işaretçi alabilirsiniz, ancak C ++ 03'te Days::Sundaygeçersizdir. (Bu üzücü). Çünkü C ++ (bir şekilde) C ile geriye doğru uyumludur ve C'nin ad alanları yoktur, bu nedenle numaralandırmaların global ad alanında olması gerekir. Yani sözdizimi basitçe:

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

Neyse ki, Mike Seymour bunun C ++ 11'de ele alındığını gözlemliyor. Değişim enumiçin enum classkendi kapsamı alır ve; bu yüzden Days::Sundaysadece geçerli değil, aynı zamanda erişmenin de tek yolu budur Sunday. Mutlu günler!


254
Neyse ki, şikayetiniz C ++ 11'de giderildi. Değişim enumiçin enum classkendi kapsamı alır ve; bu yüzden Days::Sundaysadece geçerli değil, aynı zamanda erişmenin de tek yolu budur Sunday. Mutlu günler!
Mike Seymour

11
C ++ hata mesajlarını sevmeliyim ... dilin iyi bir geri bildirim vermek için hantal olduğunu kanıtlıyorlar. Ben bir 'birincil-ifade' bir nesne veya bir kapsam veya bir tür DEĞİL başka bir şey olduğunu düşünüyorum. Belki de bir Tür bir 'ikincil-ifadedir'. Ve bir C ++ geliştiricisinin 'nokta operatörü' olarak adlandırabileceği şey, C ++ derleyicisinin yalnızca bir 'jetonu' çağırabilir. Hata mesajlarını anlamak o kadar zorlaştığında, sanırım dilde bir sorun var.
Travis

4
@Travis: en.cppreference.com/w/cpp/language/… . Birincil ifade, bir ifadedeki ilk şeydir, genellikle bir ad veya değişken veya değişmez değerdir. İkinci bölüme gelince, bir operatör değil, bir jeton dışında ve bir simge arasında büyük bir fark görmüyorum '.' tokenve dot operatorbir isimden ziyade tam sembolü gösteriyor.
Mooing Duck

@Mike Seymour Bir grup derleyicide kapsam çözümleme operatörleri olmadan numaralara erişmeye çalıştım ve işe yarıyor gibi görünüyor. C ++ 11'den itibaren tek yol olduğunu söylediniz, bazı nedenlerden dolayı enum değerlerine küresel olarak erişebiliyorum, ::
Zebrafish

1
@TitoneMaurice: Eğer varsa enum, hiçbir kapsam veya global kapsam ( ::Saturday) kullanamazsınız . Bir varsa enum class(çok farklı bir şeydir), o zaman var kullanımı Days::Saturday.
Mooing Duck

24

Bu, enum değişkeninizi beyan etmek ve karşılaştırmak için yeterli olacaktır:

enum Days {Saturday, Sunday, Tuesday, Wednesday, Thursday, Friday};
Days day = Saturday;
if (day == Saturday) {
    std::cout << "Ok its Saturday";
}

neden (gün == Günler Cumartesi) söylemek yanlıştır? aynı olmalı, peki derleyici neden bundan şikayet ediyor?
Rika

1
@ Saymanızda bildirilen değerler sınıf veya yapı üyesi değişkenleri gibi davranmaz. Bu, kullanılacak doğru sözdizimi değil
mathematician1975

2
@Hossein: çünkü Daysne bir kapsam ne de nesne. Bu bir tür. Ve Türlerin kendilerinin üyesi yoktur. std::string.clearaynı nedenden dolayı derlenemez.
Mooing Duck

8
@Hossein: Çünkü C ++ 'daki numaralar böyle çalışmaz. Kaplanmamış numaralandırmalar değerlerini çevredeki ad alanına yerleştirir; Kapsamlı olanların ( enum class2011'de yeni) kendi kapsamları vardır ve kapsam operatörü kullanılarak erişilir Days::Saturday,. Üye erişim operatörü ( .) yalnızca sınıf üyelerine erişmek için kullanılır.
Mike Seymour

@MooingDUck ve MikeSeymour Biriniz yanıtınızı cevap olarak gönderir misiniz? çünkü bu soruyu yayınlayarak tam olarak bundan sonra olduğum şey buydu;)
Rika

22

Bunların çoğu size derleme hataları vermelidir.

// note the lower case enum keyword
enum Days { Saturday, Sunday, Monday, Tuesday, Wednesday, Thursday, Friday };

Şimdi, Saturday, Sundayvb üst düzey çıplak sabitler olarak kullanılabilir ve Daysbir tür olarak kullanılabilir:

Days day = Saturday;   // Days.Saturday is an error

Ve benzer şekilde daha sonra, test etmek için:

if (day == Saturday)
    // ...

Bunlar enumonlar ediyoruz - değerleri çıplak sabitler gibidir un (C ++ 11 kullanmadığınız sürece: derleyicisinden biraz ekstra yardımıyla - -scoped enum sınıfları onlar) değil , örneğin nesne veya yapı üyeleri gibi kapsüllü ve Eğer onlara bakın edemez üyeleri arasında Days.

Aşağıdakileri tanıtan C ++ 11 ile aradığınızı bulacaksınız enum class:

enum class Days
{
    SUNDAY,
    MONDAY,
    // ... etc.
}

// ...

if (day == Days::SUNDAY)
    // ...

Bu C ++ 'ın C'den biraz farklı olduğunu unutmayın, bir tanesi C enumdeğişkenini bildirirken anahtar kelimenin kullanılmasını gerektirir :

// day declaration in C:
enum Days day = Saturday;

Soruyu güncelledim, şimdi tam olarak neyden sonra olduğumu daha net düşünüyorum :) Bu arada teşekkür ederim :)
Rika

14

Kapsamları istediğiniz gibi kullanmak için bir numara kullanabilirsiniz, sadece numaralandırmayı şu şekilde bildirin:

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

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

9

Bir dizi if-ifadesi kullanmak yerine, numaralandırmalar ifadeleri değiştirmek için kendilerini iyi borçlandırıyor

Oyunum için inşa ettiğim seviye oluşturucuda bazı numaralandırma / anahtar kombinasyonları kullanıyorum.

EDIT: Başka bir şey, benzer sözdizimi istediğiniz görüyorum;

if(day == Days.Saturday)
etc

Bunu C ++ ile yapabilirsiniz:

if(day == Days::Saturday)
etc

İşte çok basit bir örnek:

EnumAppState.h

#ifndef ENUMAPPSTATE_H
#define ENUMAPPSTATE_H
enum eAppState
{
    STARTUP,
    EDIT,
    ZONECREATION,
    SHUTDOWN,
    NOCHANGE
};
#endif

Somefile.cpp

#include "EnumAppState.h"
eAppState state = eAppState::STARTUP;
switch(state)
{
case STARTUP:
    //Do stuff
    break;
case EDIT:
    //Do stuff
    break;
case ZONECREATION:
    //Do stuff
    break;
case SHUTDOWN:
    //Do stuff
    break;
case NOCHANGE:
    //Do stuff
    break;
}

Buradaki güzel şey, derleyicilerin bir dava
açmayı

Bu durumda class enum kullanmamalısınız?
Rika

1
enum sadece bir C ++ veri tipidir. Bu yüzden yukarıda bir .h dosyasında yaptığım gibi bir enum bildirmek ve daha sonra kullanmak istediğiniz herhangi bir .cpp dosyasına bu dosyayı dahil etmek enum erişim sağlayacaktır. Sadece .cpp örneğime #include eklemeyi unuttuğumu fark ettim. Düzenleme.
Dean Knight

Ayrıca, C ++ 'daki numaralandırmaların küresel olduğunu söyleyen bir başkasını görüyorum. Deneyimlerime göre, enum'ları yukarıdaki gibi kullanarak, onlara yalnızca .h eklediğimde erişebilirim. Yani bu, küresel erişimi de durduruyor gibi görünüyor, ki bu her zaman iyidir. EDIT: Eğer doğru şeyler okuyorsam bilmeden C ++ 11 şekilde enums kullanıyorum gibi görünüyor ...
Dean Knight

9

Hâlâ C ++ 03 kullanıyorsanız ve numaralandırma kullanmak istiyorsanız, ad alanı içinde numaralandırmalar kullanmalısınız. Örneğin:

namespace Daysofweek{
enum Days {Saturday, Sunday, Tuesday,Wednesday, Thursday, Friday};
}

Numaralandırmayı ad alanının dışında,

Daysofweek::Days day = Daysofweek::Saturday;

if (day == Daysofweek::Saturday)
{
    std::cout<<"Ok its Saturday";
}

8

C ++ 11'de bulunan bir özellik olan güçlü yazılan numaralandırmalar arıyorsunuz standardında . Numaralandırmaları kapsam değerlerine sahip sınıflara dönüştürür.

Kendi kod örneğinizi kullanarak:

  enum class Days {Saturday, Sunday, Tuesday,Wednesday, Thursday, Friday};
  Days day = Days::Saturday;

  if (day == Days::Saturday)  {
    cout << " Today is Saturday !" << endl;
  }
  //int day2 = Days::Sunday; // Error! invalid

::Numaralandırmalara erişimci olarak kullanmak , C ++ 11'den önceki bir C ++ standardını hedeflerse başarısız olur. Ancak bazı eski derleyiciler bunu desteklemez, ayrıca bazı IDE'ler bu seçeneği geçersiz kılar ve eski bir C ++ std ayarlar.

GCC kullanıyorsanız, -std = c ++ 11 veya -std = gnu11 ile C + 11'i etkinleştirin .

Mutlu ol!


1
Yazmayı unuttun enum class Days { ....
Martin Hennings

Aslında. düzeltiyorum! Teşekkürler.
Alex Byrth

7

Bu C ++ ile çalışmamalıdır:

Days.Saturday

Günler, nokta operatörü ile erişebileceğiniz üyeleri içeren bir kapsam veya nesne değildir. Bu sözdizimi sadece bir C # -ismidir ve C ++ için yasal değildir.

Microsoft, kapsam operatörünü kullanarak tanımlayıcılara erişmenizi sağlayan bir C ++ uzantısını uzun süredir sürdürmektedir:

enum E { A, B, C };

A;
E::B; // works with Microsoft's extension

Ancak bu C ++ 11'den önce standart değildir. C ++ 03'te bir enumda bildirilen tanımlayıcılar yalnızca enum türünün kendisiyle aynı kapsamda bulunur.

A;
E::B; // error in C++03

C ++ 11, enum tanımlayıcılarını enum adıyla nitelemeyi yasal hale getirir ve ayrıca tanımlayıcılar için çevreleyen kapsama yerleştirmek yerine yeni bir kapsam oluşturan enum sınıflarını sunar.

A;
E::B; // legal in C++11

enum class F { A, B, C };

A; // error
F::B;

4

Ne yazık ki, enum unsurları 'küresel'. Onlara yaparak erişirsiniz day = Saturday. Bu, sahip olamayacağınız enum A { a, b } ;ve enum B { b, a } ;çatışma içinde oldukları anlamına gelir .


2
enum classC ++ 11'de kullanılana kadar . Bundan önce, kukla sınıflar yapmak zorundasınız.
chris

C ++ 11 bilmiyorum. Sorunun C ++ ile ilgili olduğunu varsayıyorum. Evet, sınıfları veya ad alanlarını kullanmak işe yarayacaktır.
Grzegorz

@Grzegorz: Bence Chris güçlü bir şekilde yazılmış numaralandırmalar sağlayan yeni tanıtılan numaralandırma sınıfından bahsediyor.
Rika

@Hossein: İşaret ettiğiniz için teşekkür ederim. Num sınıfının açıklamasını buldum ve Chris'in neden bahsettiğini biliyorum. Çok teşekkürler.
Grzegorz

@Grzegorz: Saygısızlık etmeyi kastetmedim, sadece yardımcı olabileceğimi düşündüm, olası herhangi bir yanlış anlama için özür dilerim. Tekrar Zaman ayırdığınız ve bana yardım ettiğiniz için teşekkür ederim;)
Rika

4

C ++ (C ++ 11 hariç) numaralandırmalara sahipken, içindeki değerler genel ad alanına "sızdırılır".
Sızıntılarını istemiyorsanız (ve numaralandırma türünü kullanmanız GEREKMEZ), aşağıdakileri göz önünde bulundurun:

class EnumName {  
   public:   
      static int EnumVal1;  
      (more definitions)  
};  
EnumName::EnumVal1 = {value};  
if ([your value] == EnumName::EnumVal1)  ...

3

C ++ 'daki numaralandırmalar, enum değerlerinizi bildirdiğinizde, onlara verdiğiniz adlarla maskelenen tamsayılara benzer (bu bir tanım değildir, sadece nasıl çalıştığına dair bir ipucu değildir).

Ancak kodunuzda iki hata var:

  1. Yazım enumhepsi küçük harf
  2. Days.Cumartesi gününe gerek yok .
  3. Bu numaralandırma bir sınıfta bildirilmişse, if (day == YourClass::Saturday){}

OP 16 dakika sonrası ilk (daha sonra yazım / durum değişti düzeltme 1 için düzeltme 2 ).
Peter Mortensen

1

Ben senin kök sorunu ad alanı kullanacak .yerine , kullanımı olduğunu düşünüyorum ::.

Deneyin:

enum Days {Saturday, Sunday, Tuesday, Wednesday, Thursday, Friday};
Days day = Days::Saturday;
if(Days::Saturday == day)  // I like literals before variables :)
{
    std::cout<<"Ok its Saturday";
}

Bu işe yaramaz: Days::kapsamı örneğinizde olduğu gibi kullanmak için numaralandırmayı tanımlamalı enum class Daysve C ++ 03 + Microsoft uzantısı veya C ++ 11 kullanmalısınız.
Futal

@Futal, yukarıda Borland C ++ Builder ile koştu. Lezzet / C ++ Sürümü söz konusu değildir.
James Oravec

1
Borland C ++ Builder sürümünüz C ++ 11 veya daha yenisini kullanıyor olmalıdır. Gcc ve Clang, örneğiniz -std=c++98veya ile derlenmişse hata veya uyarı verir -std=c++03. Clang oldukça açık: warning: use of enumeration in a nested name specifier is a C++11 extension.
Futal

1

Sıkı tip güvenlik ve kapsamlandırılmış numaralandırma istiyorsak, enum classC ++ 11'de kullanmak iyidir.

C ++ 98'de çalışmak zorunda kalsaydık, kapsamlandırılmış numaralandırmayı etkinleştirmek için InitializeSahib, tarafından verilen tavsiyeleri Sankullanabiliriz.

Ayrıca katı tip güvenliği de istiyorsak, aşağıdaki kod gibi bir şey uygulayabilir enum.

#include <iostream>
class Color
{
public:
    static Color RED()
    {
        return Color(0);
    }
    static Color BLUE()
    {
        return Color(1);
    }
    bool operator==(const Color &rhs) const
    {
        return this->value == rhs.value;
    }
    bool operator!=(const Color &rhs) const
    {
        return !(*this == rhs);
    }

private:
    explicit Color(int value_) : value(value_) {}
    int value;
};

int main()
{
    Color color = Color::RED();
    if (color == Color::RED())
    {
        std::cout << "red" << std::endl;
    }
    return 0;
}

Kod Effective C ++ 3rd: Item 18 sınıfındaki Ay örneğinden değiştirilir


-15

Her şeyden önce, enum'da 'E', küçük harf olarak 'e' yapın.

İkinci olarak, 'Günler' alanına 'Günler' yazın.

Üçüncü olarak ... kendinize iyi bir C ++ kitabı satın alın.


5
Maalesef tüm bu aşağı oyları aldınız (yani, cevap bunu hak ediyor), ancak bu, topluluğu 6 yıl boyunca terk etmeniz gerektiği anlamına gelmiyor. Geri dön ve bize katıl. Siz de katkıda bulunacak bir şeyiniz var. Yardımcı ol. Bilgiyi paylaş.
Gabriel Staples
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.