我想在C ++ 17中高效地双向映射一些不同类型的值(1:1映射只有很少的值)。例如考虑映射枚举值和整数,尽管该问题也适用于其他类型。目前,我正在这样做:
#include <optional>
enum class ExampleEnum { A, B, C, D, E };
class MyMapping {
public:
std::optional<int> enumToInt(ExampleEnum v) {
switch(v) {
case ExampleEnum::A:
return 1;
case ExampleEnum::B:
return 5;
case ExampleEnum::D:
return 42;
}
return std::nullopt;
}
std::optional<ExampleEnum> intToEnum(int v) {
switch(v) {
case 1:
return ExampleEnum::A;
case 5:
return ExampleEnum::B;
case 42:
return ExampleEnum::D;
}
return std::nullopt;
}
};
这具有必须写两次所有内容的明显缺点,而忘记更新其中一个功能将导致不一致。有更好的方法吗?
我需要:
我想拥有:
避免使用此类代码会更好。它们倾向于违反软件开发的基本原理之一The Open-Closed Principle。
您可以通过将MyMapping
设置得一般些来改进。让更高级别的类/函数定义映射。
class MyMapping {
public:
void registerItem(ExampleEnum eValue, int intValue)
{
enumToIntMap[eValue] = intValue;
intToEnumMap[intValue] = eValue;
}
std::optional<int> enumToInt(ExampleEnum v) {
auto iter = enumToIntMap.find(v);
if ( iter != enumToIntMap.end() )
{
return iter->second;
}
else
{
return std::nullopt;
}
}
std::optional<ExampleEnum> intToEnum(int v) {
auto iter = intToEnumMap.find(v);
if ( iter != intToEnumMap.end() )
{
return iter->second;
}
else
{
return std::nullopt;
}
}
std::map<ExampleEnum, int> enumToIntMap;
std::map<int, ExampleEnum> intToEnumMap;
};
更高级别的功能可以是:
void initMyMapping(MyMapping& mapping)
{
mapping.registerItem(A, 1);
mapping.registerItem(B, 2);
mapping.registerItem(D, 42);
}
我知道这仍然违反了开闭原则,但程度较轻。如果要为C
和E
添加映射数据,则必须为此添加代码。但是,您可以执行此操作而无需更改MyMapping
。您还可以选择在第二个功能中执行此操作,而不更改initMyMapping
。
void initMyMapping_extend(MyMapping& mapping)
{
mapping.registerItem(C, 22);
mapping.registerItem(E, 38);
}