C++ 强枚举为整数,反之亦然

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来说,它有一个问题

见:

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:。如何检查我,