C ++ 11で列挙型クラスの値を出力するにはどうすればよいですか


96

enum classC ++ 11での値を出力するにはどうすればよいですか?C ++ 03では次のようになります。

#include <iostream>

using namespace std;

enum A {
  a = 1,
  b = 69,
  c= 666
};

int main () {
  A a = A::c;
  cout << a << endl;
}

c ++ 0xでは、このコードはコンパイルされません

#include <iostream>

using namespace std;

enum class A {
  a = 1,
  b = 69,
  c= 666
};

int main () {
  A a = A::c;
  cout << a << endl;
}


prog.cpp:13:11: error: cannot bind 'std::ostream' lvalue to 'std::basic_ostream<char>&&'
/usr/lib/gcc/i686-pc-linux-gnu/4.5.1/../../../../include/c++/4.5.1/ostream:579:5: error:   initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char, _Traits = std::char_traits<char>, _Tp = A]'

Ideone.comコンパイル


1
なぜ列挙型を出力しようとしているのですか?enumクラスは、enum値とint表現を混同しないために使用されます
RiaD

回答:


122

スコープなしの列挙とは異なり、スコープ付きの列挙は暗黙的に整数値に変換できません。キャストを使用して明示的に整数に変換する必要があります:

std::cout << static_cast<std::underlying_type<A>::type>(a) << std::endl;

ロジックを関数テンプレートにカプセル化することができます。

template <typename Enumeration>
auto as_integer(Enumeration const value)
    -> typename std::underlying_type<Enumeration>::type
{
    return static_cast<typename std::underlying_type<Enumeration>::type>(value);
}

使用されます:

std::cout << as_integer(a) << std::endl;

3
これが末尾の戻り型構文を使用する理由はありますか?
Nicol Bolas

3
@NicolBolas:as_integerオープンソースライブラリの1つであるCxxReflect からコピーしました(enumeration.hppを参照)。ライブラリは、どこでも一貫して末尾の戻り値の型を使用します。一貫性のため。
James McNellis、2012

11
これは2年遅れですが、他の誰かがこの質問を見た場合、上記のキャストテクニックメソッドを使用して、単に "static_cast <int>(value)"を呼び出して整数または "static_cast <A>(intValue)"を取得できます。列挙値を取得します。intからenumまたはenumからenumに移動すると問題が発生する可能性があり、通常は設計バグの兆候であることを覚えておいてください。
ベンジャミンデンジャージョンソン

4
int(value)とA(intValue)も機能し、醜い山括弧は不要です。
Grault、2014

4
as_integerconstexpr定数式が必要なコンテキストで使用できるように定義できます。
Nawaz、

39
#include <iostream>
#include <type_traits>

using namespace std;

enum class A {
  a = 1,
  b = 69,
  c= 666
};

std::ostream& operator << (std::ostream& os, const A& obj)
{
   os << static_cast<std::underlying_type<A>::type>(obj);
   return os;
}

int main () {
  A a = A::c;
  cout << a << endl;
}

この例をそのままコピーしてコンパイルしましたg++ -std=c++0x enum.cppが、一連のコンパイラエラーが発生します-> pastebin.com/JAtLXan9。また、@ james-mcnellisからサンプルをコンパイルすることもできませんでした。
デニス

4
@Dennis underlying_typeは唯一のC ++ 11である
徳清

23

2番目の例(スコープ付き列挙型を使用する例)を、スコープなし列挙型と同じ構文を使用して機能させることができます。さらに、このソリューションは汎用的であり、スコープ付き列挙型ごとにコードを作成するのではなく、スコープ付き列挙型すべてに対して機能します(@ForEveRによって提供される回答に示されています)。

解決策はoperator<<、スコープ付き列挙型で機能する汎用関数を作成することです。このソリューションは、SFINAEを使用してstd::enable_ifおり、次のとおりです。

#include <iostream>
#include <type_traits>

// Scoped enum
enum class Color
{
    Red,
    Green,
    Blue
};

// Unscoped enum
enum Orientation
{
    Horizontal,
    Vertical
};

// Another scoped enum
enum class ExecStatus
{
    Idle,
    Started,
    Running
};

template<typename T>
std::ostream& operator<<(typename std::enable_if<std::is_enum<T>::value, std::ostream>::type& stream, const T& e)
{
    return stream << static_cast<typename std::underlying_type<T>::type>(e);
}

int main()
{
    std::cout << Color::Blue << "\n";
    std::cout << Vertical << "\n";
    std::cout << ExecStatus::Running << "\n";
    return 0;
}

typename前に必要std::underlying_type<T>::typeです。
uckelman 2015

@uckelman正解です。私の答えを更新してくれてありがとう。
James Adkison、2015

これは私にとってclangの下では機能しましたが、gcc 4.9.2の下では、<<を一緒にチェーンすると、このソリューションはエラーで失敗しますerror: cannot bind ‘std::basic_ostream<char>’ lvalue to ‘std::basic_ostream<char>&&’。これは、ストリームが一時的なものである場合、ADLが失敗し、上記のテンプレートが可能でないためと考えられます。任意のヒント?
ofloveandhate

@ofloveandhate問題を引き起こす例へのリンクを提供してもらえますか?上記のコードをgcc 4.9.2で問題なくテストし、わずかな変更を加えただけで、演算子をつなぎ合わせることで3つのcoutステートメントを1つのcoutステートメントに変換しました<<。こちらをご覧ください
James Adkison

私の声明を修正させてください。私は、クラスの外側から、クラスの内側に含まれる列挙型クラスを出力しようとしていました。上記のコードは、クラス自体に含まれていない列挙型クラスに対して実際に機能します。
ofloveandhate

10

(まだコメントすることはできません。)ジェームズ・マクネリスのすでに素晴らしい答えに対する以下の改善を提案します。

template <typename Enumeration>
constexpr auto as_integer(Enumeration const value)
    -> typename std::underlying_type<Enumeration>::type
{
    static_assert(std::is_enum<Enumeration>::value, "parameter is not of type enum or enum class");
    return static_cast<typename std::underlying_type<Enumeration>::type>(value);
}

  • constexpr:enumメンバー値をコンパイル時の配列サイズとして使用できるようにする
  • static_assert+ is_enum:関数がsthを実行することをコンパイル時に「保証」します。提案されているように、列挙のみで

ちなみに私は自分に問いかけenum classています。列挙型メンバーに数値を割り当てるときになぜ使用する必要があるのでしょうか。変換作業を検討しています。

おそらく私がenumここで提案したように、通常に戻るでしょう:C ++でフラグとして列挙型を使用する方法?


@TobySpeightの提案に基づく、static_assertなしのさらに別の(より良い)フレーバー:

template <typename Enumeration>
constexpr std::enable_if_t<std::is_enum<Enumeration>::value,
std::underlying_type_t<Enumeration>> as_number(const Enumeration value)
{
    return static_cast<std::underlying_type_t<Enumeration>>(value);
}

存在するタイプTはありstd::underlying_type<T>::typeますが、std::is_enum<T>::value偽ですか?そうでない場合、static_assertは値を追加しません。
Toby Speight 2017

1
すべてのコンパイラーでテストしたわけではありません。しかし、@ TobySpeightはあなたが正しいと思います。msvc2013は、包括的なエラーメッセージを吐き出しているようで、既存の基となる型と列挙されている型自体との1対1の対応を示唆しています。また、static_assertは実行されません。しかし:参照は、完全な列挙型が提供されていない場合、underground_typeの動作は未定義であることを示しています。そのため、static_assertは、万が一に備えて最大の理解可能なメッセージを取得するための希望にすぎません。おそらく、それをより早く/最も早く処理するように強制する可能性がありますか?
yau 2017

ああ、そうですEnumeration。完全な列挙型ではない場合、それは未定義であるとあなたは正しいです。その場合、戻り値の型で使用されているため、すでに手遅れである可能性があります。おそらくstd::enable_if<std::is_enum<Enumeration>::value, std::underlying_type<Enumeration>::type>、戻り値の型として指定できますか?もちろん、Conceptsをサポートするコンパイラーがあれば、はるかに簡単です(そしてエラーメッセージがはるかに明確になります)
Toby Speight

6

簡単に書くために、

enum class Color
{
    Red = 1,
    Green = 11,
    Blue = 111
};

int value = static_cast<int>(Color::Blue); // 111

これは、列挙型に基礎となる型が明示的に指定されている場合は機能しません
James

3

以下はC ++ 11で私のために働きました:

template <typename Enum>
constexpr typename std::enable_if<std::is_enum<Enum>::value,
                                  typename std::underlying_type<Enum>::type>::type
to_integral(Enum const& value) {
    return static_cast<typename std::underlying_type<Enum>::type>(value);
}

0

あなたはこのようなことをすることができます:

//outside of main
namespace A
{
    enum A
    {
        a = 0,
        b = 69,
        c = 666
    };
};

//in main:

A::A a = A::c;
std::cout << a << std::endl;

2
質問は列挙型クラスについて尋ねました。
Ant
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.