Bagaimana cara mengeluarkan nilai dari enum class
dalam C ++ 11? Di C ++ 03 ini seperti ini:
#include <iostream>
using namespace std;
enum A {
a = 1,
b = 69,
c= 666
};
int main () {
A a = A::c;
cout << a << endl;
}
di c ++ 0x kode ini tidak dapat dikompilasi
#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]'
disusun di Ideone.com
Jawaban:
Tidak seperti enumerasi tanpa cakupan, enumerasi terbatas tidak secara implisit dapat dikonversi menjadi nilai integernya . Anda perlu secara eksplisit mengubahnya menjadi integer menggunakan cast:
std::cout << static_cast<std::underlying_type<A>::type>(a) << std::endl;
Anda mungkin ingin merangkum logika ke dalam template fungsi:
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); }
digunakan sebagai:
std::cout << as_integer(a) << std::endl;
sumber
as_integer
dari salah satu perpustakaan open-source saya, CxxReflect (lihat enumeration.hpp ). Pustaka menggunakan tipe pengembalian jejak secara konsisten, di mana-mana. Untuk konsistensi.as_integer
dapat didefinisikanconstexpr
sedemikian rupa sehingga dapat digunakan dalam konteks di mana ekspresi konstan diperlukan.#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; }
sumber
g++ -std=c++0x enum.cpp
tetapi saya mendapatkan banyak kesalahan kompiler -> pastebin.com/JAtLXan9 . Saya juga tidak bisa mendapatkan contoh dari @ james-mcnellis untuk dikompilasi.Dimungkinkan untuk mendapatkan contoh kedua Anda (yaitu, yang menggunakan enum terbatas) untuk bekerja menggunakan sintaks yang sama seperti enum tanpa batas. Selain itu, solusinya bersifat generik dan akan berfungsi untuk semua enum cakupan, dibandingkan menulis kode untuk setiap enum cakupan (seperti yang ditunjukkan dalam jawaban yang disediakan oleh @ForEveR ).
Solusinya adalah menulis
operator<<
fungsi generik yang akan berfungsi untuk enum cakupan apa pun. Solusinya menggunakan SFINAE viastd::enable_if
dan adalah sebagai berikut.#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; }
sumber
typename
sebelumnyastd::underlying_type<T>::type
.error: cannot bind ‘std::basic_ostream<char>’ lvalue to ‘std::basic_ostream<char>&&’
. ini tampaknya karena ketika streaming bersifat sementara, ADL gagal, dan template di atas tidak memungkinkan. ada tips?cout
pernyataan menjadi satucout
pernyataan dengan merangkai<<
operator bersama. Lihat di sini(Saya belum diizinkan untuk berkomentar.) Saya akan menyarankan perbaikan berikut untuk jawaban James McNellis yang sudah hebat:
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); }
dengan
constexpr
: memungkinkan saya untuk menggunakan nilai anggota enum sebagai ukuran array waktu kompilasistatic_assert
+is_enum
: untuk 'memastikan' waktu kompilasi bahwa fungsi melakukan sth. dengan pencacahan saja, seperti yang disarankanNgomong-ngomong, saya bertanya pada diri sendiri: Mengapa saya harus menggunakan
enum class
saat saya ingin menetapkan nilai angka ke anggota enum saya ?! Mempertimbangkan upaya konversi.Mungkin saya kemudian akan kembali ke biasa
enum
seperti yang saya sarankan di sini: Bagaimana menggunakan enums sebagai flag di C ++?Namun rasa lain (lebih baik) tanpa static_assert, berdasarkan saran dari @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); }
sumber
T
yangstd::underlying_type<T>::type
ada, tapistd::is_enum<T>::value
salah? Jika tidak, makastatic_assert
tidak ada nilai tambah.Enumeration
bukan tipe enum lengkap. Dalam hal ini, mungkin sudah terlambat, karena digunakan dalam tipe pengembalian. Mungkin kita bisa menentukanstd::enable_if<std::is_enum<Enumeration>::value, std::underlying_type<Enumeration>::type>
sebagai tipe pengembalian? Tentu saja, ini jauh lebih mudah (dan pesan kesalahan jauh lebih jelas) jika Anda memiliki kompiler dengan dukungan untuk Konsep ...Untuk menulis lebih sederhana,
enum class Color { Red = 1, Green = 11, Blue = 111 }; int value = static_cast<int>(Color::Blue); // 111
sumber
Berikut ini berhasil untuk saya di 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); }
sumber
Anda bisa melakukan sesuatu seperti ini:
//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;
sumber