1

I'm already fairly sure what I'm about to ask isn't possible without creating my own enum implamentation, but I thought it was worth putting it out there in case there's something I've missed, because it would simplify a situation I come across quite often both at work and in my own projects.

Basically, I would like a generic way of returning a list of all enums in an enum class, or at least a generic way of returning all positive enums up until an enum-specific but otherwise pre-determined point. Ok, that last idea was confusing, so I'll post pseudo code of what I mean below...

A way of setting a specific enum "key?" that is used to return the number of positive enums up until the given key:

template<typename EnumType>
std::vector<EnumType> getFullEnumList()
{
    std::vector<EnumType> fullEnumList;

    for (enumIndex = 0; enumIndex < EnumType::NumEnums; enumIndex++)
        fullEnumList.push_back(static_cast<EnumType>(enumIndex));

    return fullEnumList;
}

I'm guessing this wouldn't be a practical thing to implement as stated above because the compiler doesn't care what I've called each enum class value, only it's value and class type... that all that compiler deals with in the final compilation stages right?

My first idea I guess would involve some kind of:

EnumClass::size()

...function, which I already know doesn't exist, but I don't currently know enough about the specifics of an enum class to understand why this wouldn't be possible to implement in future c++ iterations... I'm guessing it's either not possible, or it would be an undesirable extra overhead in most enum class use cases, otherwise they'd have implemented it years ago...

But to narrow down to my actual question, on top of the extra knowledge nuggets you guys could furnish me with regarding the above musings, is there some generic way of doing this I haven't thought of?

Cheers in advance for your insights,

Pete

Jesper Juhl
  • 30,449
  • 3
  • 47
  • 70
Iron Attorney
  • 1,003
  • 1
  • 9
  • 22
  • 1
    Your problem is bigger than simply getting the number of enumerators. Don't forget the enumerators don't have to name consecutive values (`enum foo { bar = 22, baz = 420000 };`) – StoryTeller - Unslander Monica Oct 21 '17 at 20:39
  • There isn't a facility specified as part of C++ itself. You could write a program that parses the definition of an enum type, and outputs source code to produce the list. That program would need to cope with values in an enum type not being consecutive, there being more than one name for a given numeric value, etc etc. If you really wanted, that program could also output code that maps an enumerated value to a string. – Peter Oct 21 '17 at 20:45
  • Sounds like you want some compile time reflection - which C++ does not have (yet). – Jesper Juhl Oct 21 '17 at 20:49
  • Not yet, but I recommend watching Herb’s Sutter’s CppCon 17’ talk which discusses this and other similar future directions https://youtu.be/4AfRAVcThyA – Danra Oct 21 '17 at 21:38

3 Answers3

2

If you are using Enums with sequential values, your could use this old trick.

Define a Max (and an optional Min) value for each Enum you have:

enum class MyEnum
{
    Sunday,
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Max,
    Min = Sunday // (Optional, see following notes)
};

Define your enumeration method as following:

template<typename EnumType>
std::vector<EnumType>
getFullEnumList(int from = (int)EnumType::Min, int to = (int)EnumType::Max)
{
    std::vector<EnumType> fullEnumList;

    for (auto enumIndex = from; enumIndex < to; enumIndex++)
        fullEnumList.push_back(static_cast<EnumType>(enumIndex));

    return fullEnumList;
}

The use of EnumType::Min and EnumType::Max as default values will protect from invocations of this method for Enum types that are not defined properly.

Note: If all your Enums use positive values only, you can avoid the decleration of Min and use int from = 0 for getFullEnumList.

And use this method trivially:

auto enumsList = getFullEnumList<MyEnum>();
-- OR --
auto enumsList = getFullEnumList<MyEnum>(2, 4);
Daniel Trugman
  • 8,186
  • 20
  • 41
  • This is the traditional way - explicit Min,Max elements. C++ could use some additional language facilities in this area. Ada '83 had attributes for first, last, min, max, pred, succ, pos, val, image (→ string), and value (string →). Don't know why we can't have them too. (It's easy to implement them according to the C++ philosophy: no cost unless used.) – davidbak Oct 21 '17 at 22:43
0

If you have some regular enum (just sequental values, not flags) you can quickly achive that by using bounding values:

enum t_MyEnum
{
    enum_begin

,   monday = enum_begin
,   tuesday
...
,   sunday  

,   enum_end
,   enum_items_cout = enum_end - enum_begin
};

The more flexibale way would be to implement some enum type traits.

// traits
template<typename TEnum> class t_Integral
{
    public: using t_Type = int;
};

template<typename TEnum> class t_FirstItem;

template<typename TEnum> class t_LastItem;

template<typename TEnum> class t_ItemsCount
{
    public: static constexpr const ::std::size_t value
    {
        static_cast<::std::size_t>
        (
            static_cast<typename t_Integral<TEnum>::t_Type>(t_LastItem<TEnum>::value)
            -
            static_cast<typename t_Integral<TEnum>::t_Type>(t_FirstItem<TEnum>::value)
            +
            1
        )
    };
};

// enum
enum class t_MyEnum
:   ::std::uint16_t
{
    monday
,   tuesday
...
,   sunday
};

// specialize traits (can also be done to third-party enums)
template<> class t_Integral<t_MyEnum>
{
    public: using t_Type = ::std::uint16_t;
};

template<> class t_FirstItem<t_MyEnum>
{
    public: static constexpr const auto value{t_MyEnum::monday};
};

template<> class t_LastItem<t_MyEnum>
{
    public: static constexpr const auto value{t_MyEnum::sunday};
};

// now we have a generic way to get enum items count and can use it somehow...
::std::array< int, t_ItemsCount<t_MyEnum>::value > items;

Enum type traits can define stuff like enum item names (as strings) and corresponding conversion function, separation of enums by kind ("sequential enum", "sparse enum", "bit flags enum"), iteration over enum values, null values and so on.

user7860670
  • 35,849
  • 4
  • 58
  • 84
0

You can solve this in a simple way by using the Qt framework if you don’t mind the dependency.

Have a look on QMetaEnum, esp. the keyCount function.

The usage is described by this accepted answer to a StackOverflow question: You basically have to attach the Q_ENUM(myEnum) macro to your enum definition myEnum in the class myEnumClass

Afterwards you get the corresponding QMetaEnum object by calling QMetaEnum myMetaEnum = QMetaEnum::fromType<myEnumClass::enumName>();

Tob
  • 286
  • 1
  • 17