Come usare enum in C ++


218

Supponiamo di avere un enumsimile:

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

Voglio creare un'istanza di questo enume inizializzarlo con un valore corretto, quindi faccio:

Days day = Days.Saturday;

Ora voglio controllare la mia variabile o istanza con un enumvalore esistente , quindi faccio:

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

Il che mi dà un errore di compilazione:

errore: espressione primaria prevista prima di "." gettone

Per essere chiari, qual è la differenza tra dire:

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

e

if (day == Saturday)

?

A cosa si riferiscono effettivamente questi due, in quanto uno è OK e uno causa un errore di compilazione?


4
lo so, voglio o sapere perché mi sta dando l'errore!
Rika,

1
È mercoledì qui. Hai troppi errori di sintassi per il compilatore C ++. A partire da 'Enum'.
Öö Tiib,

1
@Hossein, Perché gli enum non sono la stessa sintassi (e semantica) in entrambe le lingue. La prima cosa che faccio dopo aver ricevuto un errore quando provo ad usare una funzione in una nuova lingua è cercare la sintassi (o se è possibile) in quella lingua.
chris,

@chris: lo so, faccio esattamente la stessa cosa, ho ottenuto la mia risposta, ho anche aggiornato la domanda per essere più chiara. Grazie comunque;)
Rika,

17
" per quanto ne so la dichiarazione enum e l'utilizzo in queste due lingue sono gli stessi ". C'è il tuo problema, proprio lì. C # non è la stessa lingua di C ++. In particolare, hanno una sintassi diversa per gli enum.
Robᵩ

Risposte:


350

Questo codice è sbagliato:

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

Perché Daysnon è un ambito, né un oggetto. È un tipo. E i tipi stessi non hanno membri. Quello che hai scritto è l'equivalente di std::string.clear. std::stringè un tipo, quindi non puoi usarlo .. Si utilizza .su un'istanza di una classe.

Sfortunatamente, gli enum sono magici e quindi l'analogia si ferma qui. Perché con una classe, puoi fare std::string::clearper ottenere un puntatore alla funzione membro, ma in C ++ 03 Days::Sundaynon è valido. (Che è triste). Questo perché C ++ è (in qualche modo) retrocompatibile con C e C non aveva spazi dei nomi, quindi le enumerazioni dovevano essere nello spazio dei nomi globale. Quindi la sintassi è semplicemente:

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

Fortunatamente, Mike Seymour osserva che questo è stato risolto in C ++ 11. Cambia enumin enum classe ottiene il suo scopo; quindi Days::Sundaynon è solo valido, ma è l' unico modo per accedere Sunday. Giorni felici!


254
Fortunatamente, il tuo reclamo è stato risolto in C ++ 11. Cambia enumin enum classe ottiene il suo scopo; quindi Days::Sundaynon è solo valido, ma è l'unico modo per accedere Sunday. Giorni felici!
Mike Seymour,

11
Devo amare i messaggi di errore C ++ ... dimostrano che la lingua è ingombrante per dare anche un buon feedback. Presumo che una 'espressione primaria' sia un oggetto o un ambito o qualche altra cosa che NON sia un tipo. Forse un tipo è un '"espressione secondaria". E quello che uno sviluppatore C ++ potrebbe definire un 'operatore punto' il compilatore C ++ può solo chiamare un 'token'. Quando diventa così difficile capire i messaggi di errore, c'è qualcosa che non va nella lingua che penso.
Travis,

4
@Travis: en.cppreference.com/w/cpp/language/… . Un'espressione primaria è solo la prima cosa di un'espressione, di solito un nome o una variabile o un valore letterale. Per quanto riguarda la seconda parte, non vedo una grande differenza tra '.' tokene dot operator, tranne che è un token e non un operatore, e mostra il simbolo esatto, piuttosto che un nome.
Mooing Duck il

@Mike Seymour Ho provato ad accedere agli enum senza gli operatori di risoluzione dell'ambito su un gruppo di compilatori e sembra funzionare. Hai detto che dal C ++ 11 è l'unico modo, per qualche ragione posso solo accedere ai valori enum come globali, non ho bisogno del ::
Zebrafish

1
@TitoneMaurice: se ne hai uno enum, non puoi usare alcun ambito o ambito globale ( ::Saturday). Se si dispone di una enum class(che è una cosa molto diversa), allora si hanno per l'uso Days::Saturday.
Mooing Duck il

24

Questo sarà sufficiente per dichiarare la tua variabile enum e confrontarla:

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

perché è sbagliato dire se (day == Days.Satudday)? devono essere uguali, quindi perché si sta lamentando il compilatore?
Rika,

1
@Hossein i valori dichiarati nel tuo enum non si comportano come variabili di classe o membro di struttura. Questa non è la sintassi corretta da usare
matematico

2
@Hossein: perché Daysnon è un ambito, né un oggetto. È un tipo. E i tipi stessi non hanno membri. std::string.clearinoltre non riesce a compilare per lo stesso motivo.
Mooing Duck,

8
@Hossein: Perché non è così che funzionano gli enumerati in C ++. Le enumerazioni senza ambito inseriscono i loro valori nello spazio dei nomi circostante; quelli di ambito ( enum class, nuovi nel 2011) hanno il loro campo di applicazione, e sono accessibili utilizzando l'operatore campo di applicazione, Days::Saturday. L'operatore di accesso ai membri ( .) viene utilizzato solo per accedere ai membri della classe.
Mike Seymour,

@MooingDUck e MikeSeymour Uno di voi ragazzi pubblicherà la risposta come risposta? perché è esattamente quello che stavo cercando emettendo questa domanda;)
Rika,

22

Gran parte di questo dovrebbe darti errori di compilazione.

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

Ora, Saturday, Sunday, ecc può essere utilizzato come costanti nude-alto livello, e Dayspuò essere utilizzato come un tipo:

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

Allo stesso modo, per testare:

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

Questi enumvalori sono come costanti nude - sono senza ambito - con un piccolo aiuto aggiuntivo dal compilatore: (a meno che tu non stia usando le classi enum C ++ 11 ) non sono incapsulati come membri di oggetti o strutture per esempio, e non puoi riferirti a loro come membri diDays .

Avrai quello che stai cercando con C ++ 11 , che introduce un enum class:

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

// ...

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

Si noti che questo C ++ è leggermente diverso da C in un paio di modi, uno è che C richiede l'uso della enumparola chiave quando si dichiara una variabile:

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

Ho aggiornato la domanda, penso che ora sia più chiaro cosa sto esattamente cercando :) A proposito grazie :)
Rika

14

Puoi usare un trucco per usare gli ambiti come desideri, dichiarando enum in questo modo:

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

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

9

Piuttosto che usare un mucchio di istruzioni if, gli enum si prestano bene a cambiare istruzione

Uso alcune combinazioni enum / switch nel costruttore di livelli che sto costruendo per il mio gioco.

EDIT: Un'altra cosa, vedo che vuoi una sintassi simile a;

if(day == Days.Saturday)
etc

Puoi farlo in C ++:

if(day == Days::Saturday)
etc

Ecco un esempio molto semplice:

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

La cosa bella qui è che i compilatori ti diranno se ti sei perso un caso.
chris

Non dovresti usare enum di classe in questo caso?
Rika,

1
enum è solo un tipo di dati in C ++ Quindi dichiarare un enum come ho fatto sopra in un file .h, e quindi includere quel file in qualunque file .cpp in cui vuoi usarlo ti darà accesso all'enum. Ho appena notato che ho dimenticato di aggiungere #include nel mio esempio .cpp. La modifica.
Dean Knight,

Inoltre, vedo qualcun altro dire che gli enum in C ++ sono globali. Nella mia esperienza, usando enum come ho visto sopra, posso accedervi solo quando ho incluso il .h. Quindi questo sembra bloccare anche l'accesso globale, il che è sempre positivo. EDIT: Sembra che sto inconsapevolmente usando enum in un modo C ++ 11 se sto leggendo le cose nel modo giusto ...
Dean Knight

9

Se stai ancora usando C ++ 03 e vuoi usare enums, dovresti usare enums all'interno di uno spazio dei nomi. Per esempio:

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

Puoi usare l'enum fuori dallo spazio dei nomi come

Daysofweek::Days day = Daysofweek::Saturday;

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

8

Stai cercando enumerazioni fortemente tipizzate , una funzionalità disponibile in C ++ 11 standard . Trasforma le enumerazioni in classi con valori di ambito.

Usando il tuo esempio di codice, è:

  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

L'uso ::come accesso alle enumerazioni fallirà se si sceglie come target uno standard C ++ precedente C ++ 11. Ma alcuni vecchi compilatori non lo supportano, così come alcuni IDE hanno semplicemente la precedenza su questa opzione e impostato un vecchio standard C ++.

Se stai usando GCC, abilita C + 11 con -std = c ++ 11 o -std = gnu11 .

Siate felici!


1
Hai dimenticato di scrivere enum class Days { ....
Martin Hennings,

Infatti. riparandolo! Grazie.
Alex Byrth

7

Questo non dovrebbe funzionare in C ++:

Days.Saturday

Days non è un ambito o un oggetto che contiene membri a cui è possibile accedere con l'operatore punto. Questa sintassi è solo un c # -ismo e non è legale in C ++.

Microsoft ha a lungo mantenuto un'estensione C ++ che consente di accedere agli identificatori utilizzando l'operatore scope:

enum E { A, B, C };

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

Ma questo non è standard prima di C ++ 11. In C ++ 03 gli identificatori dichiarati in un enum esistono solo nello stesso ambito del tipo enum stesso.

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

C ++ 11 rende legale qualificare gli identificatori di enum con il nome di enum e introduce anche le classi di enum, che creano un nuovo ambito per gli identificatori invece di collocarli nell'ambito circostante.

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

enum class F { A, B, C };

A; // error
F::B;

4

Purtroppo, gli elementi dell'enum sono "globali". Li accedete facendo day = Saturday. Ciò significa che non puoi avere enum A { a, b } ;e enum B { b, a } ;perché sono in conflitto.


2
Fino a quando non si utilizza enum classin C ++ 11, ovvero. Prima di ciò, devi fare lezioni fittizie.
chris,

Non conosco C ++ 11. Presumo che la domanda si riferisca al C ++. Sì, usare le classi o gli spazi dei nomi farà il trucco.
Grzegorz,

@Grzegorz: penso che chris si riferisca alla classe enum appena introdotta che fornisce enumerazioni fortemente tipizzate.
Rika,

@Hossein: Grazie per averlo sottolineato. Ho trovato una spiegazione della classe num e so di cosa stava parlando Chris. Molte grazie.
Grzegorz,

@Grzegorz: non intendevo mancare di rispetto, pensavo solo che potessi essere d'aiuto, scusami per ogni probabile malinteso. Ti ringrazio ancora per il tuo tempo e aiutami;)
Rika,

4

Mentre C ++ (escluso C ++ 11) ha enumerazioni, i valori in esse contenuti vengono "filtrati" nello spazio dei nomi globale.
Se non vuoi farli trapelare (e NON DEVI usare il tipo enum), considera quanto segue:

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

3

Gli enum in C ++ sono come numeri interi mascherati dai nomi che dai loro, quando dichiari i tuoi valori enum (questa non è una definizione solo un suggerimento su come funziona).

Ma ci sono due errori nel tuo codice:

  1. Scrivi enumtutte le lettere minuscole
  2. Non ti serve Days.prima di sabato.
  3. Se questo enum è dichiarato in una classe, allora usa if (day == YourClass::Saturday){}

L'OP ha modificato l'ortografia / il caso 16 minuti dopo il post iniziale (dalla revisione 1 alla revisione 2 ).
Peter Mortensen,

1

Penso che il tuo problema di root sia l'uso di .invece di ::, che utilizzerà lo spazio dei nomi.

Provare:

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

Questo non funziona: per utilizzare l' Days::ambito come nell'esempio, è necessario definire l'enumerazione con enum class Dayse utilizzare l'estensione C ++ 03 + Microsoft o C ++ 11.
Futal

@Futal, quanto sopra è stato eseguito con Borland C ++ Builder. Sapore / Versione di C ++ non è nella domanda.
James Oravec,

1
la tua versione di Borland C ++ Builder deve utilizzare C ++ 11 o più recente. Gcc e Clang danno entrambi errori o avvisi se il tuo esempio è compilato con -std=c++98o -std=c++03. Clang è abbastanza chiaro: warning: use of enumeration in a nested name specifier is a C++11 extension.
Futal,

1

Se vogliamo la sicurezza di tipo rigoroso e enum con ambito, usare enum classè buono in C ++ 11.

Se dovessimo lavorare in C ++ 98, possiamo usare i consigli forniti da InitializeSahib, Sanper abilitare l'enum con ambito.

Se vogliamo anche la rigorosa sicurezza dei tipi, il seguente codice può implementare qualcosa del genere 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;
}

Il codice viene modificato dall'esempio della classe Month nel libro Effective C ++ 3rd: Item 18


-15

Prima di tutto, inserisci "E" in enum, "e" come minuscolo.

In secondo luogo, rilascia il nome del tipo "Giorni" in "Giorni. Giorno".

Terzo ... comprati un buon libro in C ++.


5
Mi dispiace che tu abbia ottenuto tutti questi voti negativi (voglio dire, la risposta in qualche modo lo merita), ma ciò non significa che devi lasciare la community per 6 anni. Torna indietro e unisciti a noi. Hai qualcosa anche per contribuire. Sii utile. Condividi la conoscenza.
Gabriel Staples
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.