【问题标题】:Determining number of enums in an enum class (or a specific enum value within any enum class)确定枚举类中的枚举数(或任何枚举类中的特定枚举值)
【发布时间】:2017-10-21 20:31:12
【问题描述】:

如果不创建自己的枚举实现,我已经相当确定我要问的问题是不可能的,但我认为值得把它放在那里以防我遗漏了什么,因为它会简化我在工作和自己的项目中都经常遇到这种情况。

基本上,我想要一种通用方式来返回枚举类中所有枚举的列表,或者至少是一种通用方式来返回所有正枚举,直到特定于枚举但在其他方面预先确定的点。好的,最后一个想法令人困惑,所以我将在下面发布我的意思的伪代码......

一种设置特定枚举“键”的方法?用于返回直到给定键的正枚举数:

template<typename EnumType>
std::vector<EnumType> getFullEnumList()
{
    std::vector<EnumType> fullEnumList;

    for (enumIndex = 0; enumIndex < EnumType::NumEnums; enumIndex++)
        fullEnumList.push_back(static_cast<EnumType>(enumIndex));

    return fullEnumList;
}

我猜这不会像上面所说的那样实现,因为编译器并不关心我调用每个枚举类的值,只关心它的值和类类型......所有编译器在最后的编译阶段处理吧?

我猜我的第一个想法会涉及到某种形式:

EnumClass::size()

...函数,我已经知道它不存在,但我目前对枚举类的细节还不够了解,无法理解为什么在未来的 c++ 迭代中无法实现它...我猜这是不可能的,或者在大多数枚举类用例中这将是一个不受欢迎的额外开销,否则他们会在几年前实现它......

但要缩小到我的实际问题,除了你们可以提供给我的关于上述思考的额外知识块之外,还有一些我没有想到的通用方法吗?

提前为您的见解喝彩,

皮特

【问题讨论】:

  • 您的问题不仅仅是获取枚举数的数量。不要忘记枚举器不必命名连续值 (enum foo { bar = 22, baz = 420000 };)
  • 没有将工具指定为 C++ 本身的一部分。您可以编写一个程序来解析枚举类型的定义,并输出源代码以生成列表。该程序需要处理不连续的枚举类型中的值,给定数值有多个名称等。如果您真的想要,该程序还可以输出将枚举值映射到字符串的代码.
  • 听起来你想要一些编译时反射 - C++(还没有)。
  • 还没有,但我建议观看 Herb 的 Sutter 的 CppCon 17 演讲,该演讲讨论了这个和其他类似的未来方向 youtu.be/4AfRAVcThyA

标签: c++ templates generics enums


【解决方案1】:

如果您使用具有顺序值的枚举,您可以使用这个老技巧。

为您拥有的每个 Enum 定义一个 Max(和一个可选的 Min)值:

enum class MyEnum
{
    Sunday,
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Max,
    Min = Sunday // (Optional, see following notes)
};

定义你的枚举方法如下:

template<typename EnumType>
std::vector<EnumType>
getFullEnumList(int from = (int)EnumType::Min, int to = (int)EnumType::Max)
{
    std::vector<EnumType> fullEnumList;

    for (auto enumIndex = from; enumIndex < to; enumIndex++)
        fullEnumList.push_back(static_cast<EnumType>(enumIndex));

    return fullEnumList;
}

使用EnumType::Min 和EnumType::Max 作为默认值可以防止对未正确定义的枚举类型调用此方法。

注意:如果您的所有 Enum 仅使用 正 值,您可以避免 Min 的贬值,而使用 int from = 0 代替 getFullEnumList。

然后简单地使用这个方法:

auto enumsList = getFullEnumList<MyEnum>();
-- OR --
auto enumsList = getFullEnumList<MyEnum>(2, 4);

【讨论】:

  • 这是传统方式 - 显式 Min,Max 元素。 C++ 可以在这方面使用一些额外的语言工具。 Ada '83 具有 first、last、min、max、pred、succ、pos、val、image (→ string) 和 value (string →) 的属性。不知道为什么我们也不能拥有它们。 (根据 C++ 哲学很容易实现它们:除非使用,否则无需成本。)
【解决方案2】:

如果您有一些常规枚举(只是顺序值,而不是标志),您可以通过使用边界值快速实现:

enum t_MyEnum
{
    enum_begin

,   monday = enum_begin
,   tuesday
...
,   sunday  

,   enum_end
,   enum_items_cout = enum_end - enum_begin
};

更灵活的方法是实现一些枚举类型特征。

// traits
template<typename TEnum> class t_Integral
{
    public: using t_Type = int;
};

template<typename TEnum> class t_FirstItem;

template<typename TEnum> class t_LastItem;

template<typename TEnum> class t_ItemsCount
{
    public: static constexpr const ::std::size_t value
    {
        static_cast<::std::size_t>
        (
            static_cast<typename t_Integral<TEnum>::t_Type>(t_LastItem<TEnum>::value)
            -
            static_cast<typename t_Integral<TEnum>::t_Type>(t_FirstItem<TEnum>::value)
            +
            1
        )
    };
};

// enum
enum class t_MyEnum
:   ::std::uint16_t
{
    monday
,   tuesday
...
,   sunday
};

// specialize traits (can also be done to third-party enums)
template<> class t_Integral<t_MyEnum>
{
    public: using t_Type = ::std::uint16_t;
};

template<> class t_FirstItem<t_MyEnum>
{
    public: static constexpr const auto value{t_MyEnum::monday};
};

template<> class t_LastItem<t_MyEnum>
{
    public: static constexpr const auto value{t_MyEnum::sunday};
};

// now we have a generic way to get enum items count and can use it somehow...
::std::array< int, t_ItemsCount<t_MyEnum>::value > items;

枚举类型特征可以定义诸如枚举项目名称(作为字符串)和相应的转换函数,按种类分隔枚举(“顺序枚举”,“稀疏枚举”,“位标志枚举”),枚举值的迭代,空值等等。

【讨论】:

  • 很好 - 特别是如果您使用(可变)宏来定义您需要的所有专业化......
【解决方案3】:

如果您不介意依赖关系,可以使用 Qt 框架以简单的方式解决此问题。

看看QMetaEnum,尤其是。 keyCount 函数。

这个被接受的 StackOverflow question 的答案描述了用法:您基本上必须将 Q_ENUM(myEnum) 宏附加到类 myEnumClass中的枚举定义 myEnum >

之后调用QMetaEnum myMetaEnum = QMetaEnum::fromType&lt;myEnumClass::enumName&gt;();得到对应的QMetaEnum对象

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-16
    • 2011-03-22
    相关资源
    最近更新 更多