C ++で列挙型を使用する方法


218

enum次のようなものがあるとします。

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

これのインスタンスを作成enumし、適切な値で初期化したいので、次のようにします。

Days day = Days.Saturday;

次に、変数またはインスタンスを既存のenum値で確認したいので、次のようにします。

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

これは私にコンパイルエラーを与えます:

エラー:「。」の前にプライマリ式が必要です トークン

明確にするために、言うことの違いは何ですか?

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

そして

if (day == Saturday)

これらの2つは実際には何を指しますか。1つは問題がなく、1つはコンパイルエラーの原因になります。


4
私は知っている、なぜそれが私にエラーを与えているのかを知りたい!
リカ

1
その水曜日はここ。C ++コンパイラーの構文エラーが多すぎます。「列挙型」から始まります。
OO Tiib

1
@Hossein、列挙型は両方の言語で同じ構文(およびセマンティクス)ではないため。新しい言語で機能を使用しようとしたときにエラーが発生した後、私が最初にすることは、その言語で構文を(または可能であれば)調べることです。
クリス2012

@chris:私は知っています、私は同じことを正確に行います。うまくいけば私は私の答えを得ました。また、質問をより明確にするために更新しました。ところで、ありがとうございます;)
Rika

17
私が知る限り、これら2つの言語の列挙型宣言と使用法は同じです。」そこにあなたの問題があります。C#はC ++と同じ言語ではありません。特に、列挙型の構文は異なります。
Robᵩ

回答:


350

このコードは間違っています:

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

なぜならDays、スコープでもオブジェクトでもないからです。タイプです。また、タイプ自体にはメンバーがありません。あなたが書いたものはと同等std::string.clearです。 std::stringタイプなので、使用できません.。クラスのインスタンスで使用.ます

残念ながら、列挙型は魔法なので、類推はそこで止まります。クラスをstd::string::clear使用すると、メンバー関数へのポインターを取得できますが、C ++ 03ではDays::Sunday無効です。(悲しいことです)。これは、C ++はCと(ある程度)下位互換性があり、Cには名前空間がないため、列挙型はグローバル名前空間にある必要があるためです。したがって、構文は単純です:

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

幸い、Mike Seymour氏は、これはC ++ 11で対処されていると述べています。に変更enumするenum classと、独自のスコープを取得します。これDays::Sundayは有効なだけでなく、にアクセスする唯一の方法ですSunday。幸せな日々!


254
幸い、あなたの不満はC ++ 11で対処されました。に変更enumするenum classと、独自のスコープを取得します。これDays::Sundayは有効なだけでなく、にアクセスする唯一の方法ですSunday。幸せな日々!
マイクシーモア

11
お奨めはC ++のエラーメッセージが大好きです...彼らは、言語が面倒であり、良いフィードバックを与えることさえあることを証明しています。私はそれを「一次式」はオブジェクトではないかスコープであるか、タイプではない他の何かであると考えます。おそらく、タイプは「二次式」です。また、C ++開発者が「ドット演算子」と呼ぶものは、C ++コンパイラは「トークン」しか呼び出せません。エラーメッセージを理解するのが難しくなると、言語に問題があると思います。
トラビス

4
@Travis:en.cppreference.com/w/cpp/language/…。一次式は、式の最初のものであり、通常は名前または変数またはリテラルです。第二部として、私は大きな違いが表示されていない'.' tokendot operator、それはオペレータトークンとない以外、それは正確なシンボルではなく、名前が表示されます。
Mooing Duck 2016

@Mike Seymour一連のコンパイラでスコープ解決演算子なしで列挙型にアクセスしようとしましたが、動作するようです。あなたはC ++ 11の時点でそれが唯一の方法であると述べました、何らかの理由で私はグローバルとして列挙値にアクセスでき、必要ありません::
ゼブラフィッシュ

1
@TitoneMaurice:がある場合enum、スコープを使用しないか、グローバルスコープ(::Saturday)を使用できます。あなたが持っている場合はenum class(非常に異なるものであるが)、あなたは持って使用しますDays::Saturday
Mooing Duck

24

これは、列挙型変数を宣言して比較するのに十分です。

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

(day == Days.Satudday)と言うのはなぜ間違っているのですか?それらは同じでなければならないのに、なぜコンパイラはそれについて不平を言うのですか?
リカ

1
@Hossein列挙型で宣言された値は、クラスまたは構造体のメンバー変数のように動作しません。これは正しい構文ではありません
mathematician1975

2
@Hossein:Daysはスコープでもオブジェクトでもないため。タイプです。また、タイプ自体にはメンバーがありません。 std::string.clear同じ理由でコンパイルにも失敗します。
Mooing Duck 2012

8
@Hossein:それはC ++の列挙型が機能する方法ではないためです。スコープのない列挙型は、値を周囲の名前空間に配置します。スコープ付きのもの(enum class、2011年の新機能)には独自のスコープがあり、スコープ演算子を使用してアクセスされますDays::Saturday。メンバーアクセス演算子(.)は、クラスメンバーへのアクセスにのみ使用されます。
マイクシーモア

@MooingDUckとMikeSeymourどちらかがあなたの回答を回答として投稿しますか?それはまさにこの質問を発行することで私が求めていたものだからです;)
Rika

22

これの多くはあなたにコンパイルエラーを与えるでしょう。

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

今、SaturdaySunday、などのトップレベル裸定数として使用することができ、及びDaysタイプとして使用することができます。

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

同様に後で、テストするには:

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

これらenumの値は、裸の定数のようなものです-彼らはしている国連は、コンパイラから少し余分な助けを借りて-スコープの:(あなたがC ++ 11の使用していない限り、列挙型クラスを)それらがされていないインスタンスのオブジェクトまたは構造のメンバーのようにカプセル化され、あなたはとしてそれらを参照することができないメンバーDays

C ++ 11で探しているものが手に入りますenum class

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

// ...

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

このC ++は、いくつかの点でCと少し異なります。1つは、Cはenum変数を宣言するときにキーワードを使用する必要があることです。

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

私は質問を更新しました、私は今私が正確に何をしているのかがより明確になったと思います:)ところでありがとう:)
Rika

14

トリックを使用してスコープを好きなように使用でき、列挙を次のように宣言します。

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

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

9

列挙型は一連のifステートメントを使用するのではなく、ステートメントを切り替えるのに適しています

ゲーム用に構築しているレベルビルダーで、列挙型とスイッチの組み合わせをいくつか使用しています。

編集:もう1つ、類似の構文が必要だと思います。

if(day == Days.Saturday)
etc

これはC ++で行うことができます。

if(day == Days::Saturday)
etc

これは非常に簡単な例です:

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

ここでの良いところは、あなたがケースを入れ逃した場合、コンパイラはあなたを教えてくれるということです。
クリス・

この場合、クラス列挙型を使用するべきではありませんか?
リカ

1
enumはC ++の単なるデータ型なので、上記のように.hファイルで列挙型を宣言し、そのファイルを使用したい.cppファイルに含めると、列挙型にアクセスできます。.cppの例に#includeを追加するのを忘れていることに気づきました。編集。
ディーンナイト

また、他の誰かがC ++の列挙型はグローバルであると言っているのを見ます。私の経験では、上記のように列挙型を使用して、.hを含めた場合にのみそれらにアクセスできます。したがって、これはグローバルアクセスも停止するようで、これは常に良いことです。編集:私が物事を正しく読んでいる場合、無意識に列挙型をC ++ 11の方法で使用しているようです...
Dean Knight

9

まだC ++ 03を使用していて、列挙型を使用したい場合は、名前空間内で列挙型を使用する必要があります。例えば:

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

次のように、名前空間の外で列挙型を使用できます。

Daysofweek::Days day = Daysofweek::Saturday;

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

8

C ++ 11標準で利用可能な機能である、強く型付けされた列挙型を探しています。列挙型をスコープ値を持つクラスに変換します。

独自のコード例を使用すると、次のようになります。

  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

::列挙型へのアクセサーとしての使用は、C ++ 11より前のC ++標準をターゲットにすると失敗します。ただし、一部の古いコンパイラはそれをサポートしていません。また、一部のIDEはこのオプションをオーバーライドして、古いC ++ stdを設定しているだけです。

GCCを使用している場合は、-std = c ++ 11または-std = gnu11を使用してC + 11を有効にします。

幸せになる!


1
あなたが書くのを忘れたenum class Days { ...
マーティンヘニングス

確かに。それを修正する!ありがとう。
Alex Byrth

7

これはC ++では機能しないはずです。

Days.Saturday

Daysは、ドット演算子でアクセスできるメンバーを含むスコープまたはオブジェクトではありません。この構文は単なるC#-ismであり、C ++では無効です。

マイクロソフトは、スコープ演算子を使用して識別子にアクセスできるようにするC ++拡張機能を長い間維持しています。

enum E { A, B, C };

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

しかし、これはC ++ 11より前の標準ではありません。C ++ 03では、列挙型で宣言された識別子は、列挙型自体と同じスコープにのみ存在します。

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

C ++ 11は、enum識別子をenum名で修飾することを合法にし、enumクラスを導入します。これにより、識別子を周囲のスコープに配置する代わりに、識別子の新しいスコープを作成します。

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

enum class F { A, B, C };

A; // error
F::B;

4

悲しいことに、列挙型の要素は「グローバル」です。あなたはそうすることによってそれらにアクセスしますday = Saturday。あなたが持つことができないことを意味enum A { a, b } ;し、enum B { b, a } ;彼らが競合しているため。


2
enum classC ++ 11で使用するまでです。その前に、ダミークラスを作成する必要があります。
クリス2012

C ++ 11を知らない。私は質問がC ++に言及していると想定しています。はい、クラスまたは名前空間を使用するとうまくいきます。
Grzegorz 2012

@Grzegorz:私はクリスが強く型付けされた列挙型を提供する新しく導入された列挙型クラスを参照していると思います。
リカ

@ホセイン:指摘いただきありがとうございます。私はnumクラスの説明を見つけました、そして私はクリスが何について話していたかを知っています。どうもありがとう。
Grzegorz 2012

@Grzegorz:私はちょうど私が残念に任意の可能性misunderstanding.Iのために再度お時間をいただき、ありがとうございます、私を助けて、助けかもしれないと思った、失礼に意味するものではありませんでした。)
リカ

4

C ++(C ++ 11を除く)には列挙型がありますが、それらの値はグローバル名前空間に「リーク」されます。
それらをリークさせたくない場合(および列挙型を使用する必要がない場合)は、次のことを考慮してください。

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

3

C ++の列挙型は、列挙型の値を宣言するときに、指定した名前でマスクされた整数のようなものです(これは定義であり、動作のヒントにすぎません)。

ただし、コードには2つのエラーがあります。

  1. enumすべて小文字で綴る
  2. Days.前の土曜日は必要ありません。
  3. この列挙型がクラスで宣言されている場合は、 if (day == YourClass::Saturday){}

OPは、最初の投稿から16分後にスペル/ケースを変更しました(リビジョン1からリビジョン2へ)。
Peter Mortensen

1

あなたの根本的な問題は、名前空間を使用するの.代わりにを使用することだと思います::

試してください:

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

これは機能しませんDays::。例のようにスコープを使用するには、列挙型をenum class DaysC ++ 03 + Microsoft拡張またはC ++ 11で定義して使用する必要があります。
Futal

@Futal、上記はBorland C ++ Builderで実行されました。フレーバー/ C ++のバージョンは問題ではありません。
James Oravec

1
Borland C ++ BuilderのバージョンはC ++ 11以降を使用している必要があります。GccとClangはどちらも、例が-std=c++98またはでコンパイルされた場合にエラーまたは警告を出します-std=c++03。Clangは非常に明確ですwarning: use of enumeration in a nested name specifier is a C++11 extension
Futal

1

厳密な型安全性とスコープ付き列挙型が必要な場合はenum class、C ++ 11で使用するのが適切です。

C ++ 98で作業する必要がある場合は、スコープ列挙型を有効にするためにInitializeSahibSanからのアドバイスを使用できます。

厳密な型安全性も必要な場合は、次のコードでのようなものを実装できます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;
}

このコードは、Effective C ++ 3rd:Item 18のクラスMonthの例から変更されています。


-15

まず、列挙型で「E」、小文字で「e」にします。

次に、「Days.Saturday」にタイプ名「Days」をドロップします。

3番目...良いC ++の本を自分で購入します。


5
申し訳ありませんが、これらすべての反対票を獲得しました(つまり、答えはそれに値するものです)。戻って参加してください。あなたにも貢献する何かがあります。役立つ。知識を共有します。
ガブリエルステープルズ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.