Is it possible to determine the number of elements

2019-03-09 06:51发布

Is it possible to determine the cardinality of a c++ enum class:

enum class Example { A, B, C, D, E };

I tried to use sizeof, however, it returns the size of an enum element.

sizeof(Example); // Returns 4 (on my architecture)

Is there a standard way to get the cardinality (5 in my example) ?

7条回答
家丑人穷心不美
2楼-- · 2019-03-09 07:06

No , you have to write it in the code.

查看更多
老娘就宠你
3楼-- · 2019-03-09 07:08
enum class TEST
{
    BEGIN = __LINE__
    , ONE
    , TWO
    , NUMBER = __LINE__ - BEGIN - 1
};

auto const TEST_SIZE = TEST::NUMBER;

// or this might be better 
constexpr int COUNTER(int val, int )
{
  return val;
}

constexpr int E_START{__COUNTER__};
enum class E
{
    ONE = COUNTER(90, __COUNTER__)  , TWO = COUNTER(1990, __COUNTER__)
};
template<typename T>
constexpr T E_SIZE = __COUNTER__ - E_START - 1;
查看更多
不美不萌又怎样
4楼-- · 2019-03-09 07:09

There is one trick based on X()-macros: image, you have the following enum:

enum MyEnum {BOX, RECT};

Reformat it to:

#define MyEnumDef \
    X(BOX), \
    X(RECT)

Then the following code defines enum type:

enum MyEnum
{
#define X(val) val
    MyEnumDef
#undef X
};

And the following code calculates number of enum elements:

template <typename ... T> void null(T...) {}

template <typename ... T>
constexpr size_t countLength(T ... args)
{
    null(args...); //kill warnings
    return sizeof...(args);
}

constexpr size_t enumLength()
{
#define XValue(val) #val
    return countLength(MyEnumDef);
#undef XValue
}

...
std::array<int, enumLength()> some_arr; //enumLength() is compile-time
std::cout << enumLength() << std::endl; //result is: 2
...
查看更多
Deceive 欺骗
5楼-- · 2019-03-09 07:18

One trick you can try is to add a enum value at the end of your list and use that as the size. In your example

enum class Example { A, B, C, D, E, ExampleCount };
查看更多
爱情/是我丢掉的垃圾
6楼-- · 2019-03-09 07:21

Not directly, but you could use the following trick:

enum class Example { A, B, C, D, E, Count };

Then the cardinality is available as (int)Example::Count.

Of course, this only works nicely if you let values of the enum be automatically assigned, starting from 0. If that's not the case, you can manually assign the correct cardinality to Count, which is really no different from having to maintain a separate constant anyway:

enum class Example { A = 1, B = 2, C = 4, D = 8, E = 16, Count = 5 };

The one disadvantage is that the compiler will allow you to use Example::Count as an argument for an enum value -- so be careful if you use this! (I personally find this not to be a problem in practice, though.)

查看更多
戒情不戒烟
7楼-- · 2019-03-09 07:27
constexpr auto TEST_START_LINE = __LINE__;
enum class TEST { // Subtract extra lines from TEST_SIZE if an entry takes more than one 
    ONE = 7
  , TWO = 6
  , THREE = 9
};
constexpr auto TEST_SIZE = __LINE__ - TEST_START_LINE - 3;

This is derived from UglyCoder's answer but improves it in three ways.

  • There are no extra elements in the type_safe enum (BEGIN and SIZE) (Cameron's answer also has this problem.)
    • The compiler will not complain about them being missing from a switch statement (a significant problem)
    • They cannot be passed inadvertently to functions expecting your enum. (not a common problem)
  • It does not require casting for use. (Cameron's answer has this problem too.)
  • The subtraction does not mess with the size of the enum class type.

It retains UglyCoder's advantage over Cameron's answer that enumerators can be assigned arbitrary values.

A problem (shared with UglyCoder but not with Cameron) is that it makes newlines and comments significant ... which is unexpected. So someone could add an entry with whitespace or a comment without adjusting TEST_SIZE's calculation.

查看更多
登录 后发表回答