Before you ask, I\'ve looked and looked for this on SO, and cannot find a solid answer.
I need to be able to dynamically iterate over an enum that has non-incre
the beginnings of a solution involving no macros and (almost) no runtime overhead:
#include
#include
#include
#include
template using has_value = std::integral_constant;
template
struct better_enum
{
static constexpr size_t size = sizeof...(EnumValues);
using value_array = int[size];
static const value_array& values() {
static const value_array _values = { EnumValues::value... };
return _values;
}
using name_array = const char*[size];
static const name_array& names() {
static const name_array _names = { EnumValues::name()... };
return _names;
}
using enum_values = boost::mpl::vector;
struct iterator {
explicit iterator(size_t i) : index(i) {}
const char* name() const {
return names()[index];
}
int value() const {
return values()[index];
}
operator int() const {
return value();
}
void operator++() {
++index;
}
bool operator==(const iterator& it) const {
return index == it.index;
}
bool operator!=(const iterator& it) const {
return index != it.index;
}
const iterator& operator*() const {
return *this;
}
private:
size_t index;
};
friend std::ostream& operator<<(std::ostream& os, const iterator& iter)
{
os << "{ " << iter.name() << ", " << iter.value() << " }";
return os;
}
template
static iterator find() {
using iter = typename boost::mpl::find::type;
static_assert(iter::pos::value < size, "attempt to find a value which is not part of this enum");
return iterator { iter::pos::value };
}
static iterator begin() {
return iterator { 0 };
}
static iterator end() {
return iterator { size };
}
};
struct Pig : has_value<0> { static const char* name() { return "Pig";} };
struct Dog : has_value<7> { static const char* name() { return "Dog";} };
struct Cat : has_value<100> { static const char* name() { return "Cat";} };
struct Horse : has_value<90> { static const char* name() { return "Horse";} };
struct Monkey : has_value<1000> { static const char* name() { return "Monkey";} };
using animals = better_enum<
Pig,
Dog,
Cat,
Horse
>;
using namespace std;
auto main() -> int
{
cout << "size : " << animals::size << endl;
for (auto v : animals::values())
cout << v << endl;
for (auto v : animals::names())
cout << v << endl;
cout << "full iteration:" << endl;
for (const auto& i : animals())
{
cout << i << endl;
}
cout << "individials" << endl;
auto animal = animals::find();
cout << "found : " << animal << endl;
while (animal != animals::find()) {
cout << animal << endl;
++animal;
}
// will trigger the static_assert auto xx = animals::find();
return 0;
}
output:
size : 4
0
7
100
90
Pig
Dog
Cat
Horse
full iteration:
{ Pig, 0 }
{ Dog, 7 }
{ Cat, 100 }
{ Horse, 90 }
individials
found : { Dog, 7 }
{ Dog, 7 }
{ Cat, 100 }