Wie kann ich den Wert eines enum class
in C++ 11 ausgeben? In C++ 03 ist es so:
#include <iostream>
using namespace std;
enum A {
a = 1,
b = 69,
c= 666
};
int main () {
A a = A::c;
cout << a << endl;
}
in C++ 0x kompiliert dieser Code nicht
#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]'
zusammengestellt auf Ideone.com
Im Gegensatz zu einer nicht begrenzten Aufzählung ist eine bereichsabhängige Aufzählung nicht implizit in ihren ganzzahligen Wert konvertierbar. Sie müssen explizit mithilfe eines Casts in eine Ganzzahl konvertieren:
std::cout << static_cast<std::underlying_type<A>::type>(a) << std::endl;
Möglicherweise möchten Sie die Logik in eine Funktionsvorlage einkapseln:
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);
}
benutzt als:
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;
}
Es ist möglich, Ihr zweites Beispiel (d. H. Das mit einem Enumerat mit Gültigkeitsbereich) mit derselben Syntax wie mit einem unbeschränkten Enum zu arbeiten. Darüber hinaus ist die Lösung generisch und funktioniert für alle Aufzählungsumfänge, anstatt Code für jedes Aufzählungsumlauf zu schreiben (wie in answer von @ForEveR angegeben).
Die Lösung besteht darin, eine generische operator<<
-Funktion zu schreiben, die für jedes Enum für Bereiche geeignet ist. Die Lösung verwendet SFINAE via std::enable_if
und lautet wie folgt.
#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;
}
(Ich darf noch nicht kommentieren.) Ich würde folgende Verbesserungen an der bereits großartigen Antwort von James McNellis vorschlagen:
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);
}
mit
constexpr
: Damit kann ich einen Enum-Member-Wert als Arraygröße für die Kompilierzeit verwendenstatic_assert
+ is_enum
: Um die Kompilierungszeit zu "sicherstellen", dass die Funktion sth. nur mit Aufzählungen, wie vorgeschlagenÜbrigens frage ich mich: Warum sollte ich enum class
verwenden, wenn ich meinen Enumerationsmitgliedern Zahlenwerte zuweisen möchte ?! Berücksichtigen Sie den Konvertierungsaufwand.
Vielleicht würde ich dann auf normale enum
zurückgehen, wie ich hier vorgeschlagen habe: Wie benutze ich Enums als Flags in C++?
Noch ein (besserer) Geschmack ohne static_assert, basierend auf einem Vorschlag von @TobySpeight:
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);
}
Um einfacher zu schreiben,
enum class Color
{
Red = 1,
Green = 11,
Blue = 111
};
int value = static_cast<int>(Color::Blue); // 111
Folgendes hat für mich in C++ 11 funktioniert:
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);
}