2017-02-10 123 views
0

在我的项目中,我使用了多个枚举类,我需要根据需要使用它们轻松地进行转换。他们基本上描述相同的事物,但命名不同,以使代码更容易处理。下面是枚举类:为枚举类重载转换运算符

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

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

在tetroType每个值对应于网格块的值(FE tetroType :: I =网格块:: 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; 
} 
+1

铸造不应该“轻松”完成。它*应该*是详细和明确的,这样你就不会过于宽松地施放。必须编写'gridBlock grid = toGridBlock(tetroType :: I)'和'string texture = toString(grid);''是一件好事*。 –

+0

我一直在寻找最优雅和正确的方式来做到这一点,我已经有了将一个转换为另一个的功能,但我不确定这是否是正确的方式。此外,该功能应该在哪里?它应该在头文件中与枚举声明一起使用吗?这就是为什么我认为如果可能的话,演员将是最优雅的解决方案。 –

+0

这是基于意见的,但个人而言,我更喜欢在自己的头文件中使用转换函数,所以我只需要在需要时包含它们。再次,标准库本身不(总是)这样做。例如,''包含'std :: string' *和*各种'std :: to_string'函数。 –

回答

1

答案很简单:不使用enum class,使用普通enum相反,它们可以被隐式转换到其基本类型(默认int)。

在C++ 11,enum class是一个强大的别名,其中HAS被铸造而成。

0

如果你接受这样的事实,你必须保持两个枚举一致的其他的一个定义,使每个gridBlock需要从tetroType一个值,那么您可以覆盖operator==在比较无缝地使用它们,覆盖不同运营商(例如<<=)模仿不同类型之间的分配。

事情是这样的:

#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<<=这样的运算符是很安全的,因为它们在任何情况下都没有定义。

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