是否有可能确定一个C ++枚举类的元素的数量?(Is it possible to determin

2019-08-17 02:42发布

是否有可能确定一个C ++的基数enum class

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

我试图用sizeof ,但它返回一个枚举元素的大小。

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

有没有获得(在我的例子5)的基数的标准方式?

Answer 1:

不是直接的,但你可以使用下面的技巧:

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

然后基数是可作为(int)Example::Count

当然,这只是工作得很好,如果你让枚举值是自动分配的,从0开始如果不是的话,你可以手动分配正确的基数来算,这是需要维护一个独立的恒定真的没有什么不同无论如何:

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

一个缺点是,编译器将允许您使用Example::Count作为一个枚举值的参数-如果你使用这个,所以要小心! (我个人觉得这不是在实践中的问题,虽然)。



Answer 2:

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;

这是源自UglyCoder的答案 ,但它提高了在三个方面。

  • 有在type_safe枚举(没有多余的元素BEGINSIZE )( 卡梅隆的回答也有这个问题。)
    • 编译器不会抱怨他们是从一个switch语句失踪(一显著的问题)
    • 它们不能被不经意地传递给需要的枚举功能。 (不是常见的问题)
  • 它不需要铸造使用。 ( 卡梅隆的回答了这个问题了。)
  • 减法不乱用枚举类类型的大小。

它保留UglyCoder的超过优势卡梅隆的回答是普查员可以指定任意值。

一个问题(共享UglyCoder但不与卡梅伦 )是,它使新行和评论显著......这是意想不到的。 因此,有人可能会增加与空白条目或不调整注释TEST_SIZE的计算。



Answer 3:

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;


Answer 4:

一个窍门,你可以尝试是在列表的末尾添加一个枚举值,并用其作为大小。 在你的榜样

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


Answer 5:

不,你必须把它写在代码中。



Answer 6:

有基于X()一个绝招 - 宏:图像,你有以下枚举:

enum MyEnum {BOX, RECT};

其重新格式化为:

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

然后将以下代码定义枚举类型:

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

而下面的代码计算枚举元素的个数:

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
...


Answer 7:

对于C ++ 17可以使用magic_enum :: enum_count从LIB https://github.com/Neargye/magic_enum magic_enum :: enum_count() - > 4。



Answer 8:

还可以考虑static_cast<int>(Example::E) + 1 ,它消除了额外的元件。



Answer 9:

如果你使用的升压转换器的预处理工具,您可以获取使用count BOOST_PP_SEQ_SIZE(...)

例如,一个可以定义CREATE_ENUM如下宏:

#include <boost/preprocessor.hpp>

#define ENUM_PRIMITIVE_TYPE std::int32_t

#define CREATE_ENUM(EnumType, enumValSeq)                                  \
enum class EnumType : ENUM_PRIMITIVE_TYPE                                  \
{                                                                          \
   BOOST_PP_SEQ_ENUM(enumValSeq)                                           \
};                                                                         \
static constexpr ENUM_PRIMITIVE_TYPE EnumType##Count =                     \
                 BOOST_PP_SEQ_SIZE(enumValSeq);                            \
// END MACRO   

然后,调用宏:

CREATE_ENUM(Example, (A)(B)(C)(D)(E));

会生成以下代码:

enum class Example : std::int32_t 
{
   A, B, C, D, E 
};
static constexpr std::int32_t ExampleCount = 5;

这仅与问候到升压预处理器工具划伤表面。 例如,您的宏还可以从字符串转换工具和ostream的操作符强类型枚举定义为/。

更多关于这里升压预处理器工具: https://www.boost.org/doc/libs/1_70_0/libs/preprocessor/doc/AppendixA-AnIntroductiontoPreprocessorMetaprogramming.html


顺便说一句,我碰巧与@FantasticMrFox强烈同意,额外的Count ,如果使用中公认的答案使用枚举值会产生编译器警告头痛嘉豪switch语句。 我发现unhandled case编译器警告代码更安全的维护是非常有用的,所以我不想破坏它。



文章来源: Is it possible to determine the number of elements of a c++ enum class?