C++ 强枚举为整数,反之亦然
以下是我的源代码(作为答案),如何实现底层的_值,以及如何实现_枚举函数。 基础_值-没问题。 但是,对enum来说,它有一个问题 见:C++ 强枚举为整数,反之亦然,c++,c++11,enums,strongly-typed-enum,C++,C++11,Enums,Strongly Typed Enum,以下是我的源代码(作为答案),如何实现底层的_值,以及如何实现_枚举函数。 基础_值-没问题。 但是,对enum来说,它有一个问题 见: enum类E{a=1,b=3,c=5}; 自动e_a=utils::底层_值(e::a)//好啊 E t=utils::to_enum(2);//编译,但它是不正确的。我想这里一定有例外吧? 问:如何正确实现枚举?尽管对这个问题有评论,但这可以在C++11中完成,尽管要做到这一点而不重复代码,您最终必须将枚举类声明包装在宏中。这可能使我的回答不合适,这取决
enum类E{a=1,b=3,c=5};
自动e_a=utils::底层_值(e::a)//好啊
E t=utils::to_enum(2);//编译,但它是不正确的。我想这里一定有例外吧?
问:如何正确实现枚举?尽管对这个问题有评论,但这可以在C++11中完成,尽管要做到这一点而不重复代码,您最终必须将
枚举类
声明包装在宏中。这可能使我的回答不合适,这取决于你的需要。无论哪种方式,执行选中的转换都需要一些机器,因此我将最后讨论宏
基本思想是使用constexpr
函数扫描阵列:
#include <iostream>
#include <stdexcept>
enum class E { a = 1, b = 3, c = 5 };
constexpr E values[] = {E::a, E::b, E::c};
constexpr size_t count = sizeof(values) / sizeof(E);
constexpr E to_enum(int value, size_t index = 0)
{
return
index >= count ? throw std::runtime_error("invalid integer") :
static_cast<int>(values[index]) == value ? values[index] :
to_enum(value, index + 1);
}
constexpr E converted = to_enum(3);
// Will not compile if uncommented.
// constexpr E bad_converted = to_enum(2);
int main()
{
std::cout << static_cast<int>(converted) << std::endl;
return 0;
}
因此,在本例中,\uu VA\u ARGS\uu
将是标记a=1、b=3、c=5
。因此,我们可以在宏中声明枚举本身,如下所示:
enum class TypeName { __VA_ARGS__ };
然而,我们不能简单地宣布:
constexpr TypeName values[] = { __VA_ARGS__ };
因为这扩展到
constexpr TypeName values[] = { a = 1, b = 3, c = 5 };
不在范围内(缺少<代码>类型名:://>在每个值前面),并且由于数组初始化器中的额外赋值操作符,所以不是有效的C++。我先解决第二个问题。您需要定义这样一个类:
template <typename E>
class swallow_assignment {
public:
E _value;
constexpr explicit swallow_assignment(E value) : _value(value)
{
}
template <typename Any>
constexpr const swallow_assignment& operator =(Any other) const
{
return *this;
}
constexpr operator E() const
{
return _value;
}
};
现在将是一个有效的初始值设定项。这可以通过映射宏完成。我不会在这里详细介绍,因为这是一个完全不同的主题,但是可以在这里找到这样一个宏。Boost可能还有一个更好的。无论您使用的是什么宏,我都假定它的签名是PP\u映射(前缀,\uu VA\u ARGS)
。然后,整个枚举的最终宏定义的草图变为:
#define ENUM_CLASS(TypeName, __VA_ARGS__) \
enum class TypeName { __VA_ARGS__ }; \
constexpr TypeName values[] = \
{ PP_MAP((swallow_assignment<TypeName>)TypeName::, \
__VA_ARGS__) }; \
constexpr size_t count = sizeof(values) / sizeof(TypeName);
#定义枚举类(TypeName,uu VA_ARGS_uu)\
枚举类类型名{{uuuu VA_ARGS}\
constexpr TypeName值[]=\
{PP_映射((swallow_赋值)类型名::\
__VA_ARGS_uu)}\
constexpr size\u t count=sizeof(值)/sizeof(类型名);
您可能希望将这些定义填充到traits类型的专门化中,以便可以将此宏与多个enum类
(否则名为values
的数组将发生冲突)。但是,如果将值设置为traits类的静态成员,则可能必须使用弱符号来避免链接问题
最后几点留作练习,因为这个答案已经太长了:)我有一个库,可以完成上述所有工作,尽管它包装了enum
,而不是为enum类提供traits专门化。但是,有一个未发布的分支具有enum class
/traits的组合。您可以在此处看到库:。库的::\u from_integral()
方法对应于问题中的to_enum
函数,它同时进行运行时和编译时转换。尽管对问题有评论,但这可以在C++11中完成,尽管要在不重复代码的情况下完成此操作,最终必须将enum类
声明包装到宏中。这可能使我的回答不合适,这取决于你的需要。无论哪种方式,执行选中的转换都需要一些机器,因此我将最后讨论宏
基本思想是使用constexpr
函数扫描阵列:
#include <iostream>
#include <stdexcept>
enum class E { a = 1, b = 3, c = 5 };
constexpr E values[] = {E::a, E::b, E::c};
constexpr size_t count = sizeof(values) / sizeof(E);
constexpr E to_enum(int value, size_t index = 0)
{
return
index >= count ? throw std::runtime_error("invalid integer") :
static_cast<int>(values[index]) == value ? values[index] :
to_enum(value, index + 1);
}
constexpr E converted = to_enum(3);
// Will not compile if uncommented.
// constexpr E bad_converted = to_enum(2);
int main()
{
std::cout << static_cast<int>(converted) << std::endl;
return 0;
}
因此,在本例中,\uu VA\u ARGS\uu
将是标记a=1、b=3、c=5
。因此,我们可以在宏中声明枚举本身,如下所示:
enum class TypeName { __VA_ARGS__ };
然而,我们不能简单地宣布:
constexpr TypeName values[] = { __VA_ARGS__ };
因为这扩展到
constexpr TypeName values[] = { a = 1, b = 3, c = 5 };
不在范围内(缺少<代码>类型名:://>在每个值前面),并且由于数组初始化器中的额外赋值操作符,所以不是有效的C++。我先解决第二个问题。您需要定义这样一个类:
template <typename E>
class swallow_assignment {
public:
E _value;
constexpr explicit swallow_assignment(E value) : _value(value)
{
}
template <typename Any>
constexpr const swallow_assignment& operator =(Any other) const
{
return *this;
}
constexpr operator E() const
{
return _value;
}
};
现在将是一个有效的初始值设定项。这可以通过映射宏完成。我不会在这里详细介绍,因为这是一个完全不同的主题,但是可以在这里找到这样一个宏。Boost可能还有一个更好的。无论您使用的是什么宏,我都假定它的签名是PP\u映射(前缀,\uu VA\u ARGS)
。然后,整个枚举的最终宏定义的草图变为:
#define ENUM_CLASS(TypeName, __VA_ARGS__) \
enum class TypeName { __VA_ARGS__ }; \
constexpr TypeName values[] = \
{ PP_MAP((swallow_assignment<TypeName>)TypeName::, \
__VA_ARGS__) }; \
constexpr size_t count = sizeof(values) / sizeof(TypeName);
#定义枚举类(TypeName,uu VA_ARGS_uu)\
枚举类类型名{{uuuu VA_ARGS}\
constexpr TypeName值[]=\
{PP_映射((swallow_赋值)类型名::\
__VA_ARGS_uu)}\
constexpr size\u t count=sizeof(值)/sizeof(类型名);
您可能希望将这些定义填充到traits类型的专门化中,以便可以将此宏与多个enum类
(否则名为values
的数组将发生冲突)。但是,如果将值设置为traits类的静态成员,则可能必须使用弱符号来避免链接问题
最后几点留作练习,因为这个答案已经太长了:)我有一个库,可以完成上述所有工作,尽管它包装了enum
,而不是为enum类提供traits专门化。但是,有一个未发布的分支具有enum class
/traits的组合。您可以在此处看到库:。库的::_from_integral()
方法对应于您问题中的to_enum
函数,它执行运行时和编译时转换。枚举与其基础类型具有相同的范围,只是对某些值使用了特殊名称E(2)
是一个非常好的值。我知道这个规则。但是t
不等于E:。如何检查我,