Reputation: 3533
Hello I have the following enum
enum params_Solver {
params_Solver_Lorem,
params_Solver_Ipsum,
params_Solver_Simply,
params_Solver_Dummy,
params_Solver_Test,
params_Solver_Typesetting,
params_Solver_Industry,
params_Solver_Scrambled
};
what I want to do is try to doing something like this pseudocode:
for (auto enum_member: params_Solver)
{
print(index, enum_member); // output looks like this: "0, params_Solver_Lorem", "1, params_Solver_Ipsum" etc
}
Is there anyway to achieve this?
Edit: I do not have the control over enum. This enum is provided by a different file from a 3rd part library. I can probably copy it but not change the original enum. I want to write the members of the enum library to a different file.
Upvotes: 3
Views: 639
Reputation: 275500
No. The reflection proposal, which does what you want, may arrive in [c++23].
Without it, you can copy paste the enum
, possibly quoting it, into an array, and iterating over the copy.
constexpr char const* members[] {
"params_Solver_Lorem",
"params_Solver_Ipsum",
//etc
};
then just do a for loop over that.
for (char const* const& enum_member: members)
{
auto index = static_cast<long long unsigned>(&enum_member-members);
printf("%llu, %s\n", index, enum_member);
}
Upvotes: 1
Reputation: 87
Common way
You could add an item at the end of your enumeration this way:
enum params_Solver {
params_Solver_Lorem,
params_Solver_Ipsum,
params_Solver_Simply,
params_Solver_Dummy,
params_Solver_Test,
params_Solver_Typesetting,
params_Solver_Industry,
params_Solver_Scrambled,
Last
};
And loop over it with:
for (int i = params_Solver_Lorem; i != Last; i++) {
// some code
}
This solution does not work if you assign values to your enum members other than the default ones though.
Other way
You can use a regular array without having to add a last element. However the syntax is quite redundant as you have to specify yourself the members of the enum:
constexpr params_Solver members[] {
params_Solver_Lorem,
params_Solver_Ipsum,
params_Solver_Simply,
params_Solver_Dummy,
params_Solver_Test,
params_Solver_Typesetting,
params_Solver_Industry,
params_Solver_Scrambled
};
You can then iterate over the enum using:
for (auto m: members) {
// Some code
}
Upvotes: 3
Reputation: 5321
C++ does not provide intrinsic support for what you are trying to do.
You can add a some boilerplate to accomplish what you want, so that the code that is using the range of the enum is not aware of the enums. In the code example, that knowledge is encapsulated in the params_Solver_Range
helper class.
#include <iostream>
#include <stdexcept>
#include <utility>
using std::ostream;
using std::cout;
using std::underlying_type_t;
using std::logic_error;
namespace {
enum class params_Solver {
Lorem,
Ipsum,
Simply,
Dummy,
Test,
Typesetting,
Industry,
Scrambled
};
auto operator<<(ostream& out, params_Solver e) -> ostream& {
#define CASE(x) case params_Solver::x: return out << #x
switch(e) {
CASE(Lorem);
CASE(Ipsum);
CASE(Simply);
CASE(Dummy);
CASE(Test);
CASE(Typesetting);
CASE(Industry);
CASE(Scrambled);
}
#undef CASE
throw logic_error("unknown params_Solver");
}
auto operator+(params_Solver e) {
return static_cast<underlying_type_t<decltype(e)>>(e);
}
auto operator++(params_Solver& e) -> params_Solver& {
if (e == params_Solver::Scrambled) throw logic_error("increment params_Solver");
e = static_cast<params_Solver>(+e + 1);
return e;
}
class params_Solver_Range {
bool done = false;
params_Solver iter = params_Solver::Lorem;
public:
auto begin() const -> params_Solver_Range const& { return *this; }
auto end() const -> params_Solver_Range const& { return *this; }
auto operator*() const -> params_Solver { return iter; }
bool operator!=(params_Solver_Range const&) const { return !done; }
void operator++() {
if (done) throw logic_error("increment past end");
if (iter == params_Solver::Scrambled) done = true;
else ++iter;
}
};
} // anon
int main() {
for (auto e : params_Solver_Range()) {
cout << +e << ", " << e << "\n";
}
}
Upvotes: 1
Reputation: 6131
All values representable in the underlying type of the enum are valid values of the enum, whether they are given a name or not, and iterating over a 64-bit enum range might take longer than you'd care to wait... :)
Another complication, if you mean to iterate over just the named enumerators, that's possible, but takes more work, and some considerations. As already stated, if you do not give any custom values to your enumerators, then they will start at zero and increment. However, you can put gaps in the numbers, you can jump backwards, you can have repeats. Do two enumerators with the same value count as one iteration or one per name? Different situations will have different answers.
If you do this without custom values for your enumerators, you can put an extra "dummy" value at the end of the list and treat it as the count of the enumerators. But it will be wrong if you have gaps, duplicates, or start at a value other than 0. It also can fail if someone adds new enumerator values after the dummy value.
There are some 3rd party libraries that can help with this. If you don't mind a bit of extra code, the "Better Enums" open source library is very useful header-only library. https://github.com/aantron/better-enums It gives meta data over your enums with a nice syntax, allowing iterators, ranged for loop use, converting to/from string names and some more.
Upvotes: 1
Reputation: 122565
No. At least not directly. Enums are actually not a set of constants. Rather they are a type that comes with a set of named constants. Difference is: for example 42
is a completely valid value of params_Solver
, it just has no name.
A common way to enable iteration is to add a sentinel value:
enum params_Solver {
params_Solver_Lorem,
params_Solver_Ipsum,
params_Solver_Simply,
params_Solver_Dummy,
params_Solver_Test,
params_Solver_Typesetting,
params_Solver_Industry,
params_Solver_Scrambled,
num_params_Solver // <----
};
And then iterate from 0
till num_params_Solver
. The nice thing is that you can add another constant and num_params_Solver
will still be correct. The limitation is that it only works for enums without custom values.
Upvotes: 5