【问题标题】:Overloading cast operator for enum class为枚举类重载强制转换运算符
【发布时间】:2017-02-10 18:39:04
【问题描述】:

在我的项目中,我使用了多个枚举类,我需要根据需要在哪里使用它们轻松地在它们之间进行转换。它们基本上描述了相同的东西,但名称不同,以使代码更易于使用。以下是枚举类:

enum class tetroType {
    None, I, O, T, J, L, S, Z
};

enum class gridBlock {
    Empty, Blue, Green, Orange, Purple, Red, Teal, Yellow
};

tetroType 中的每个值对应于 gridBlock 中的一个值(fe tetroType::I = gridBlock::Teal),但第一个保存有关 tetronimo 形状的信息(在 tetronimo 类中),第二个保存有关颜色的信息块(在网格类中)。我知道我可以只使用一个枚举,但这样你就不会丢失任何信息。如果可能的话,我还需要将它转换成字符串。这就是我想使用它的方式:

gridBlock grid = (gridBlock)tetroType::I;
string texture = (string)grid;

现在我设置它的方式是这样的。每当我需要将一个枚举转换为另一个枚举或字符串时,我都会在其他方法的中间使用此开关:

switch (type) {
case tetroType::I:
    block = gridBlock::Teal;
    break;
case tetroType::O:
    block = gridBlock::Yellow;
    break;
case tetroType::T:
    block = gridBlock::Purple;
    break;
case tetroType::J:
    block = gridBlock::Blue;
    break;
case tetroType::L:
    block = gridBlock::Orange;
    break;
case tetroType::S:
    block = gridBlock::Green;
    break;
case tetroType::Z:
    block = gridBlock::Red;
    break;
case tetroType::None:
    block = gridBlock::Empty;
}

【问题讨论】:

  • 铸造不应该“轻易”完成。它应该是详细而明确的,这样你就不会过于随意地进行转换。必须写 gridBlock grid = toGridBlock(tetroType::I)string texture = toString(grid); 是一件的事情。
  • 我一直在寻找最优雅和最正确的方法,并且我已经拥有将一个转换为另一个的功能,但我不确定它是否是正确的方法。该功能应该在哪里?它应该与枚举声明一起在头文件中吗?这就是为什么我认为如果可能的话,演员表操作符将是最优雅的解决方案。
  • 这有点基于意见,但就我个人而言,我更喜欢将转换函数放在自己的标题中,这样我只需要在需要时才包含它们。再说一次,标准库本身并不(总是)这样做。例如,<string> 包含 std::string 各种 std::to_string 函数。

标签: c++ c++11 enums casting


【解决方案1】:

简单的答案:不要使用enum class,而是使用普通的enum,它们可以隐式转换为它们的底层类型(默认int)。

在 C++ 11 中,enum class 是一个强别名,可以从中转换。

【讨论】:

    【解决方案2】:

    您应该考虑将枚举类重载为整数(这是 C++ 11 的一项功能)。

    enum class tetroType : int {
        I = 1, O = 2, T = 3, J = 4, L = 5, S = 6, Z = 7, NONE
    };
    
    enum class gridBlock : int {
        Blue = 1, Green = 2, Orange = 3, Purple = 4, Red = 5, Teal = 6, Yellow = 9, EMPTY
    };
    

    从这里您可以使用 ether C Style typecasting 或 static_cast 编写基本转换

    gridBlock ConvertTetro(tetroType type){
        return static_cast<gridBlock>(static_cast<int>(type));
    }
    
    gridBlock ConvertTetro(tetroType type){
        return (gridBlock)((int)((type)));
    }
    

    这将匹配任何网格块到相等的 tetrotypes,如果没有匹配的类型,将默认为 gridBlock::EMPTY。如果需要,这个函数应该很容易弄清楚如何走另一条路。从这里您需要匹配两者之间的 int 值。

    您还可以使用 char 值作为 char 文字('A'、'b'、'!')使用

    enum class enumName : char
    

    只要有两种基础类型,这将起作用

    【讨论】:

      【解决方案3】:

      如果您接受这样一个事实,即您必须保持两个枚举之一的定义与另一个一致,以便每个 gridBlock 都从 tetroType 中获取一个值,那么您可以覆盖 operator== 以无缝地使用它们比较并覆盖不同的运算符(例如&lt;&lt;=)以模拟不同类型之间的分配。

      类似这样的:

      #include <iostream>
      #include <type_traits>
      #include <cassert>
      
      using namespace std;
      
      enum class tetroType {
          None, I, O, T, J, L, S, Z
      };
      
      enum class gridBlock {
          Empty = static_cast<std::underlying_type<tetroType>::type>(tetroType::None), 
          Blue = static_cast<std::underlying_type<tetroType>::type>(tetroType::I), 
          Green = static_cast<std::underlying_type<tetroType>::type>(tetroType::O), 
          Orange = static_cast<std::underlying_type<tetroType>::type>(tetroType::T), 
          Purple = static_cast<std::underlying_type<tetroType>::type>(tetroType::J), 
          Red = static_cast<std::underlying_type<tetroType>::type>(tetroType::L), 
          Teal = static_cast<std::underlying_type<tetroType>::type>(tetroType::S), 
          Yellow = static_cast<std::underlying_type<tetroType>::type>(tetroType::Z)
      };
      
      bool operator==(const tetroType& t, const gridBlock& g) { return static_cast<gridBlock>(t) == g; }
      bool operator==(const gridBlock& g, const tetroType& t) { return static_cast<gridBlock>(t) == g; }
      
      bool operator!=(const tetroType& t, const gridBlock& g) { return static_cast<gridBlock>(t) != g; }
      bool operator!=(const gridBlock& g, const tetroType& t) { return static_cast<gridBlock>(t) != g; }
      
      gridBlock& operator<<=(gridBlock& g, tetroType t) { g = static_cast<gridBlock>(t); return g; }
      tetroType& operator<<=(tetroType& t, gridBlock g) { t = static_cast<tetroType>(g); return t; }
      
      int main() {
        tetroType t1 = tetroType::I, t2 = tetroType::O;
        gridBlock g1 = gridBlock::Blue, g2 = gridBlock::Green;
      
        gridBlock g3;
        g3 <<= t1;
        tetroType t3;
        t3 <<= g2;
      
      
        assert(t1 == g1);
        assert(t1 != g2);
        assert(g3 == t1);
        assert(t3 == g2);
      
          return 0;
      }
      

      虽然此解决方案简洁明了,但它非常神秘且晦涩,因此您最好清楚地记录此行为。但通常使用enum class 覆盖operator&lt;&lt;= 之类的运算符是非常安全的,因为它们在任何情况下都没有定义。

      请注意,您可以在值之间使用自定义映射,但如果您不需要它们,因为您可以将一个值与另一个初始化,因此无需手动映射它们。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-18
        • 1970-01-01
        • 1970-01-01
        • 2011-02-04
        • 1970-01-01
        • 2023-03-18
        相关资源
        最近更新 更多