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 でコンパイル
スコープのない列挙とは異なり、スコープのある列挙は暗黙的に整数値に変換できません。 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;
#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;
}
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;
}
(まだコメントすることはできません。)ジェームス・マクネリスのすでに素晴らしい答えに以下の改善を提案します。
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);
}
より簡単に書くには、
enum class Color
{
Red = 1,
Green = 11,
Blue = 111
};
int value = static_cast<int>(Color::Blue); // 111
以下は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);
}