根据C ++中的常量值生成一个枚举

问题描述

是否可以基于C ++中的常量创建枚举?

如果我的常量值为5,我希望枚举数具有如下5个元素

typedef enum {
LIC_0,LIC_1,LIC_2,LIC_3,LIC4,} licfiles_t;

如果我的常数为10,我希望枚举数改为这样,

typedef enum {
LIC_0,LIC5,LIC6,LIC7,LIC8,LIC9,} licfiles_t;

我想要这个的原因是,我有一个常量“ MaxLicenses”,现在定义为30,并且有一个对应的枚举器,其中包含30个枚举值。如果有人将“ MaxLicenses”更改为20,那么他们也不必麻烦更改枚举数。这是我的基本想法。

解决方法

如果愿意稍微更改语法,可以使用它。

  enum class Licence : unsigned {
    LIC_FIXED,LIC_FLOATING,LIC_MAGIC,LIC_NUMBERED
  };
  
  const int MaxLicence = 20;
  
  consteval Licence LIC(unsigned l) {
      if (l >= MaxLicence) throw "Invalid licence";
      return Licence(l+(unsigned)Licence::LIC_NUMBERED);
  }

现在您可以拥有:

  auto l1  = LIC(1);   // OK
  auto l19 = LIC(19);  // OK
  auto l42 = LIC(42);  // Compile-time error,invalid licence

  auto x = 3;
  auto lx =  LIC(x);   // Compile-time error,x is not a constant

如果您真的想花哨的话,可以创建一个用户定义的文字运算符,以便编写例如19_LIC而不是LIC(19)


函数LIC可能不是那么有用,因为您不提前知道MaxLicence,因此您不知道例如LIC(19)有效。但是如果您真的想要的话,可以拥有它。

一个更有用的版本可能不是保密的,而是在运行时将许可证号转换为Licence 类型的值,当值超出范围时会报告错误。

,

不,不可能有枚举数取决于常数。

以复杂的构建过程为代价,您可以使用元编程:编写一个生成枚举定义和常量定义的程序。


理想情况下,常量应定义为枚举数之一。这样,它必须与其他枚举数匹配:

enum licfiles_t {
    LIC_0,LIC_1,LIC_2,LIC_3,LIC4,MaxLicenses // 5
};
,

模板不能应用于枚举项,因此您必须使用预处理器宏。宏不允许递归到它们自己,但是您仍然可以为“最多N个”解决方案展开它们。例如,对于最多128个许可证,您可以执行以下操作:

#define LICD_0
#define LICD_1 LIC_0
#define LICD_2 LICD_1,LIC_1
#define LICD_3 LICD_2,LIC_2
/* ... */
#define LICD_128 LICD_127,LIC_127
#define _LIC(n) LICD_##n /* jump to N unrolls */
#define LIC(n) _LIC(n)   /* to unpack MaxLicenses */

LIC(n)将泛型NLIC_0LIC_<N-1>)枚举项。您可以像这样将其与MaxLicences配对:

#define MaxLicenses 30

typedef enum {
    LIC(MaxLicenses)
} licfiles_t;

static_assert(LIC_29 == 29,"");
//static_assert(LIC_30 == 30,""); // compile error,LIC_30 not defined

演示:https://godbolt.org/z/b1E1KG

当然,输入所有内容很麻烦,因此您可以编写一个小程序来生成代码:

#define MaxSupportedLicenses 128
std::cout << "#define LICD_0" << std::endl;
std::cout << "#define LICD_1 LIC_0" << std::endl;
for (int i=2; i <= MaxSupportedLicenses; ++i) {
    std::cout << "#define LICD_" << i << " LICD_" << (i - 1) << ",LIC_" << (i - 1) << std::endl;
}