拥有:
enum class A : int {
FirstA,
SecondA,
InvalidB
};
enum class B : int {
FirstB,
SecondB,
InvalidB
};
如何启用这样的功能?
B b = mapper[A::FirstA];
A a = mapper[B::SecondB];
一种可能的解决方案是创建一个 Mapper
模板类,它允许通过构造函数中的初始值设定项列表指定映射,例如:
Mapper<A, B> mapper(
{
{A::FirstA, B::SecondB},
{A::SecondA, B::FirstB}
},
{A::InvalidA, B::InvalidB} // this is for conversions, where no mapping is specified
);
但在内部,这需要妥协 - 要么是两个映射(从 A
到 B
以及从 B
到 A
) >) 或一张 map ,例如从 A
到 B
以及对 B
到 A
转换的线性搜索)。
是否可以在标准 C++14
中实现此功能,因此:
- 不使用双层容器
- 两个方向的查找性能同样出色
- 定义和使用映射相对简单(内部实现不需要)
根据要求,:
- 它不是身份映射(即
A
中的值未映射到B
的相同基础值 A
和B
的底层类型可能不同- 映射在编译时已知
?
最佳答案
您可以使用函数模板和完全特化轻松完成此操作。您使主模板返回无效的大小写,然后特化将返回您想要的映射。
如果你有
template<A>
B mapper() { return B::InvalidB; }
template<B>
A mapper() { return A::InvalidA; }
然后您可以添加所有映射值,例如
template<>
B mapper<A::FirstA>() { return B::SecondB; }
template<>
B mapper<A::SecondA>() { return B::FirstB; }
template<>
A mapper<B::FirstB>() { return A::SecondA; }
template<>
A mapper<B::SecondB>() { return A::FirstA; }
然后你会这样调用它
B b = mapper<A::FirstA>();
A a = mapper<B::SecondB>();
这会让你根本没有容器。您甚至可以制作一些宏来使这更容易,例如
#define MAKE_ENUM_MAP(from, to) \
template<from> \
auto mapper() { return to::Invalid; } \
template<to> \
auto mapper() { return from::Invalid; }
#define ADD_MAPPING(from_value, to_value) \
template<> \
auto mapper<from_value>() { return to_value; } \
template<> \
auto mapper<to_value>() { return from_value; }
然后你会像这样使用它们
MAKE_ENUM_MAP(A, B)
ADD_MAPPING(A::FirstA, B::SecondB)
ADD_MAPPING(A::SecondA, B::FirstB)
为您生成所有代码。上述版本使用单个枚举值 Invalid
来表示映射的无效情况。如果您不想这样做,可以向宏添加 from
和 to
值以用于无效映射,例如
#define MAKE_ENUM_MAP(from, from_value, to, to_value) \
template<from> \
auto mapper() { return to_value; } \
template<to> \
auto mapper() { return from_value; }
你会这样调用它
MAKE_ENUM_MAP(A, A::InvalidA, B, B::InvalidB)
关于c++ - 有效的双向作用域枚举映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55361167/