Alexey Starinsky
Alexey Starinsky

Reputation: 4305

Is it possible to define a macro that defines an enum class and GetCount() method returning the count of enum elements?

I was able to define macro that defines an old-style enum and GetCount() method returning the count of enum elements:

#define DEFINE_FLAGS_ENUM(EnumName, ...) \
struct EnumName { \
    enum { __VA_ARGS__ }; \
    static constexpr std::size_t GetCount() { return std::max({__VA_ARGS__}) + 1;} \
};

With enum class my first idea was:

template <class T> struct EnumTraits;

#define NDA_FLAGS_ENUM(EnumName, ...) \
enum class EnumName { __VA_ARGS__ }; \
template<> struct EnumTraits<EnumName> { static constexpr std::size_t GetCount() { return std::max({__VA_ARGS__}) + 1; }};

but this does not compile, because VA_ARGS should be prepended with 'EnumName::'.

Upvotes: 2

Views: 218

Answers (1)

Hiroki
Hiroki

Reputation: 2880

enum

As suggested in comments, as for your first macro DEFINE_FLAGS_ENUM, std::max does not seem to work. Thus I propose an alternative way for it.

Since our enum is defined as an anonymous one in the class EnumName, we can define the tuple of them and detect the size of it at compile-time as follows. So this macro would well work for you:

#include <tuple>

#define DEFINE_FLAGS_ENUM(EnumName, ...)                  \
struct EnumName                                           \
{                                                         \
    enum { __VA_ARGS__ };                                 \
                                                          \
    static constexpr std::size_t GetCount()               \
    {                                                     \
        using T = decltype(std::make_tuple(__VA_ARGS__)); \
        return std::tuple_size<T>::value;                 \
    }                                                     \
};

enum class

For the enum class, we can reuse the above method as follows. Here, instead of counting the elements of enum class, we again count the ones of enum which is hidden in the class EnumTraits<EnumName> as a private member:

#include <tuple>

template <class T> struct EnumTraits;

#define NDA_FLAGS_ENUM(EnumName, ...)                     \
enum class EnumName { __VA_ARGS__ };                      \
template<>                                                \
struct EnumTraits<EnumName>                               \
{                                                         \
private:                                                  \
    enum { __VA_ARGS__ };                                 \
                                                          \
public:                                                   \
    static constexpr std::size_t GetCount()               \
    {                                                     \
        using T = decltype(std::make_tuple(__VA_ARGS__)); \
        return std::tuple_size<T>::value;                 \
    }                                                     \
};

Then we can define an enum and enum class as follows:

DEMO

// enum.
DEFINE_FLAGS_ENUM(Animal, Dog, Cat)
static_assert(Animal::GetCount() == 2);

// enum class.
NDA_FLAGS_ENUM(Vehicle, Car, Train, AirPlain)
static_assert(EnumTraits<Vehicle>::GetCount() == 3);

Upvotes: 3

Related Questions