【问题标题】:Applying a rule on how to increment an enum应用关于如何增加枚举的规则
【发布时间】:2015-05-02 17:58:53
【问题描述】:

有没有办法改变枚举设置其常量值的方式?通常它会增加一个,但我想应用其他规则。在 PAWN 中这会起作用

enum (<<=1) {
 a = 1,//0b001
 b,//0b010
 c//0b100
}

有没有办法在 C++ 中做到这一点?

【问题讨论】:

  • 感谢您的快速回答。实际上我想创建很多在开发过程中可能会改变的常量,所以我必须一直改变它。不幸的是,手动操作不是一个很好的解决方案
  • 在这种情况下,我会按照我的做法将枚举放在一个单独的文件中并创建一个生成器(例如在 Python 中)以根据您的规范创建枚举。

标签: c++ enums increment rule


【解决方案1】:

不是自动的,但您可以手动指定每个值

enum X {
  a = 0x01,
  b = 0x02,
  c = 0x04
};

【讨论】:

  • @sharptooth 我不明白你怎么能用模板做到这一点。如果你能提供一个方法,我会很感兴趣。
  • @no,因为我不知道如何模板化枚举或枚举值。
  • @sharptooth 请举个例子来支持你的说法。
  • @sharptooth:嗯,没有。
  • 我用示例添加了一个单独的答案。
【解决方案2】:

您可以使用模板元编程自动执行此转换过程:

template<int by>
struct OneShlBy {
    enum { Value = OneShlBy<by - 1>::Value << 1 };
};

template<>
struct OneShlBy<0> {
    enum { Value = 1 };
};

enum X {
    a = OneShlBy<0>::Value,
    b = OneShlBy<1>::Value,
    c = OneShlBy<2>::Value
};

【讨论】:

  • 如果您必须对每个常量应用 OneShlBy,直接使用移位运算符“a = 1, b = 1
【解决方案3】:

假设 C++11,一种方法是

constexpr int func(int x)
{
     return x << 1;
}

enum X
{
   a = 1,
   b = func(a),
   c = func(b)
};

func() 然后可用于在连续命名值之间实现您喜欢的任何关系。

在 C++11 之前,替代方案可能包括

enum X
{
   a = 1,
   b = a << 1,
   c = b << 1
};

或(使用宏)

#define func(x) x << 1
enum X
{
   a = 1,
   b = func(a),
   c = func(b)
};
#undef func

【讨论】:

    【解决方案4】:

    对于您给出的特定示例(枚举本质上是单词中的标志)的一种常见方法是使用两个枚举,一个用于位索引,第二个枚举用于实际位值:

    enum {
       b_a,             // 0
       b_b,             // 1
       b_c,             // 2
       b_d,             // 3
    };
    
    enum {
       a = 1 << b_a,    // 1
       b = 1 << b_b,    // 2
       c = 1 << b_c     // 4
       d = 1 << b_d     // 8
    };
    

    我知道这并不理想,但它避免了显式的文字常量。一些讨厌的东西可以用宏来隐藏,你可能认为这是一件好事,也可能不是。

    【讨论】:

      【解决方案5】:

      你所做的一切都很好:

      #include <iostream>
      
      enum x {
         a = 0b001
       , b = 0b010
       , c = 0b100
      };
      
      int main()
      {
          std::cout << x::a << '\n';
          std::cout << x::b << '\n';
          std::cout << x::c << '\n';
      }
      

      注意:这只是在引入二进制文字的C++14中的标准。

      否则可以使用移位运算符指定位位置:

      enum x {
            a = 1 << 0
          , b = 1 << 1
          , c = 1 << 2
      };
      

      如果您希望节省一些维护工作,另一种可能性是根据先前定义的 enums 定义每个 enum

      enum x {
            a = 1
          , b = a << 1
          , c = b << 1
          , d = c << 1
          , e = d << 1
      };
      

      这意味着你可以相对轻松地在中间添加一个元素:

      enum x {
            a = 1
          , b = a << 1
          , z = b << 1 // new element added
          , c = z << 1 // only need to adjust one other
          , d = c << 1
          , e = d << 1
      };
      

      【讨论】:

      • 不幸的是,MS Visual Studio 尚未实现 C++14 标准(二进制文字)。我想我会使用移位运算符,即使我必须编辑整个枚举器,如果我删除或添加一个常量。
      • @neophoenix 我添加了一种方法,可以更轻松地维护长列表枚举。
      【解决方案6】:

      窃取伟大的idea of Rob,有一种方法可以指定如何增加枚举的值,虽然这不是很自动,但只要你的枚举始终具有相同的字段,你就可以这样做:

      template <typename T, T(*INC)(const T), T start = {}>
      struct managed_enum
      {
          enum
          {
              a = start,
              b = INC(a),
              c = INC(b),
          };
      };
      

      使用此模板,您可以执行以下操作:

      template<typename T>
      constexpr T shift_left(const T value) { return value << 1; }
      
      using shifted = managed_enum<int, shift_left<int>, 1>;
      

      您要查找的枚举上的哪些结果 (see here)。好吧,shifted 不是枚举,而是结构,希望没关系。

      定义不同的增量函数,可以自动增加不同的枚举族,只要它们都只有managed_enum这三个值(a,b,@ 987654329@):

      template<typename T>
      constexpr T shift_left(const T value) { return value << 1; }
      
      template<typename T>
      constexpr T increment(const T value) { return value + 1; }
      
      template<typename T>
      constexpr T bicrement(const T value) { return value + 2; }
      
      using shifted   = managed_enum<int, shift_left<int>, 1>;
      using increment = managed_enum<int, increment<int>>;
      using bicrement = managed_enum<int, bicrement<int>>;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-08-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-21
        • 1970-01-01
        相关资源
        最近更新 更多