web-dev-qa-db-ja.com

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

C++ 11でenum classの値を出力するにはどうすればよいですか? 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 でコンパイル

80
Adi

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

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;
103
James McNellis
#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;
}
36
ForEveR

2番目の例(つまり、スコープ付き列挙型を使用する例)を、スコープなし列挙型と同じ構文を使用して機能させることができます。さらに、ソリューションは汎用的であり、すべてのスコープ付き列挙型に対して機能しますが、各スコープ付き列挙型に対してコードを記述することはできません( answer で提供される @ ForEveR )。

解決策は、スコープ付き列挙型で機能する汎用のoperator<<関数を作成することです。ソリューションでは、- SFINAEstd::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;
}
18
James Adkison

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

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:コンパイル時に配列サイズとして列挙型メンバー値を使用できるようにします
  • 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);
}
9
yau

より簡単に書くには、

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

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

以下は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
NutCracker