简体   繁体   中英

Getting all values from an enum

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
    }
};

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.

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!

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 })?

If you're tagging the question as C++ I advise you to give up with the C way of doing things, so the better way to do this in C++ is using a std::vector :

class Class1{
    enum Foos{
        FOO_1 = 2,
        FOO_X = 1,
        FOO_BAR = 6
    };
public:
    std::vector<int> GetFoos()
    {
        // return all enum values
        return {FOO_1, FOO_X, FOO_BAR};
    }
};

You can use it this way:

Class1 c1;
auto foos = c1.GetFoos();
std::cout << "I have " << c1.size() << " foos:\n";
for (const auto &foo : foos) std::cout << foo << '\n';

If you don't want to create the vector at runtime, you can create it once declaring it static:

class Alpha{
    enum Alphas{
        BETA = 0b101010,
        GAMMA = 0x20,
        EPSILON = 050
    };
    static const std::vector<int> m_alphas;
public:
    const std::vector<int> &GetAlphas()
    {
        return m_alphas;
    }
};

// https://isocpp.org/wiki/faq/ctors#explicit-define-static-data-mems
const std::vector<int> Alpha::m_alphas = {BETA, GAMMA, EPSILON};

Live demo

I know that is a burden to maintain but since there's no way to iterate the values of an enum, all the code that tries to iterate them is a burden as well.

Maybe in the following answer you can find something useful to iterate enums in a better way for your goals:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM