it-swarm.com.de

Wie kann ich den Wert einer Enum-Klasse in C++ 11 ausgeben

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

65
Adi

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;
86
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;
}
30
ForEveR

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;
}
15
James Adkison

(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 verwenden
  • static_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);
}
9
yau

Um einfacher zu schreiben,

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

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

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);
}
0
NutCracker