Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting all values from an enum

Tags:

c++

enums

I have classes in the style of Class1 (see code). An enum and a function to get all the values from the enum. The values (FOO_1, FOO_2 etc) differ from Class to Class as well as the number of values (sizeof(Foos)). I call the function once to get the sizeof the enum, reserve memory and with the second call I want to get all the values to *pFoos (2,1,6 in the sample code). Is there a better way then using an array with all the values in it (size_t arr[3] ={FOO_1 , FOO_X, FOO_BAR })?

class Class1{
    enum Foos{
        FOO_1 = 2,
        FOO_X = 1,
        FOO_BAR = 6
    }
};

Class1::GetFoos(size_t* pFoos, size_t* pSize)
{
    size_t len = sizeof(Foos);
    if (len > *pSize)
    {   //Call function once to get the size
        *pSize= len ;
        return -1;
    }
    for(size_t i = 0; i< *pSize; i++)
    {
       //copy all enum values to pFoos
    }
};
like image 871
tzippy Avatar asked Jun 08 '15 12:06

tzippy


People also ask

Which method is used to retrieve all values from enum?

GetValues(Type) Retrieves an array of the values of the constants in a specified enumeration.

Can you forEach an enum?

Enums don't have methods for iteration, like forEach() or iterator(). Instead, we can use the array of the Enum values returned by the values() method.


2 Answers

Disclaimer: shameless plug – I am the author.

Reflective enums are possible in C++. I wrote a header-only library that captures a bunch of "patterns" at compile time and gives you syntax like this:

ENUM(Class1, int, FOO_1 = 2, FOO_X = 1, FOO_BAR = 6)

size_t count = Class1::_size;

for (size_t index = 0; index < Class1::_size; ++index)
    do_anything(Class1::_values()[index]);

What it does internally is use the macro to generate an array of the values that you have declared, kind of like in your question, and use a bunch of other tricks to allow you to use initializers naturally. It then provides iterators and other things on top of the array.

Here is a link: https://github.com/aantron/better-enums

EDIT – internals

Here is a pseudocode sketch of what it does internally. The reason I am only giving a "sketch" is because there are a bunch of issues to consider when doing this portably. I will touch on all the most important elements.

ENUM(Class1, int, FOO_1 = 2, FOO_X = 1, FOO_BAR = 6)

notionally expands to

struct Class1 {
    enum _enumerated { FOO_1 = 2, FOO_X = 1, FOO_BAR = 6 };

    // Fairly obvious methods for how to iterate over _values and
    // _names go here. Iterators are simply pointers into _values
    // and _names below.

    static size_t _size = sizeof(_values) / sizeof(int);

    int _value;
};

int _values[] = {(fix_t<Class1>)Class1::FOO_1 = 2,
                 (fix_t<Class1>)Class1::FOO_X = 1,
                 (fix_t<Class1>)Class1::FOO_BAR = 6};
const char *_names[] = {"FOO_1 = 2", "FOO_X = 1", "FOO_BAR = 6"};

This is done by using variadic macros and stringization. The methods that deal with strings treat not only \0, but also space and equals as terminators, which allows them to ignore the initializers in the stringized constants that you see in _names.

The type fix_t is necessary because having assignments inside an array initializer is not valid C++. What that type does is take on the value of the enum, then ignore the assignment by an overloaded assignment operator, and then return the original value. A sketch:

template <typename Enum>
struct fix_t {
    Enum _value;

    fix_t(Enum value) : _value(value) { }
    const fix_t& operator =(int anything) const { return *this; }
    operator Enum() const { return _value; }
};

This makes the _values array possible declare even in the presence of initializers.

Of course, these arrays need to be prefixed so that you can have more than one enum like this. They also need to have the same as "extern inline" linkage for functions, so that they are shared between multiple compilation units.

like image 95
antron Avatar answered Nov 07 '22 13:11

antron


Until c++ will get reflection you will not get any data from your enum! Simply you can not get "all" values from an enum. A enum is simply a kind of namespace where some constants can be defined and may be enumerated automatically. Not more at all. You have no text representation, no count information, no value to text information!

like image 29
Klaus Avatar answered Nov 07 '22 14:11

Klaus