计数枚举C 自动

Count on enum C++ automatic

本文关键字:自动 枚举      更新时间:2023-10-16

在C 中编写枚举时,我会出现模式。就是这样:

class Player
{
public:
    class State
    {
    public:
        typedef enum
        {
            Stopped, 
            Playing, 
            Paused
        }PossibleValues;  
        static const int Count() {return Paused+1;};
        static const PossibleValues Default() {return Stopped;};
    };
    //...
}

这解决了一些通常的枚举问题,例如外部名称空间的污染等。但是我仍然不喜欢一件事:count()是手动完成的。我只有两种方法知道如何做:这是从最后一个 1计算出来的;或编写普通的硬编码。

问题是:是否有某种方法,例如使用自动获得计数的预处理器宏,将其放在count()方法之后?注意:我不想在枚举内有最后一个称为计数的假元素,污染它!

预先感谢!

更新1:

在标准C 11(部分)中,关于实施N4428枚举反射的有趣讨论,以提出更高级的枚举。

更新2:

有趣的文档N4451-静态反射(修订3)在其第3.16、3.17、3.17、a.7,a.8方面关于元元素和元元素。

更新3:

我看到了https://bytes.com/topic/c/answers/127908-numeric_limits-limits-pecialization#post4444962之后,使用枚举类来解决另一个有趣的模式。如果枚举类的枚举列表是连续整数的,通过定义其最大值和最小值,我们可以检查一个值是否属于它。

如果在Player::State上使用Count()方法的目的是检查值是否在枚举中,则使用Numeric_Limits方法可以实现该目的,甚至是优越的,因为不需要枚举列表开始带有零值的项目!

enum class Drink
{
    Water,
    Beer,
    Wine,
    Juice,
};

#pragma push_macro("min")
#undef min
#pragma push_macro("max")
#undef max
namespace std
{
    template <> class numeric_limits < Drink >
    {
    public:
        static const/*expr*/ bool is_specialized = true;
        static const/*expr*/ Drink min() /*noexcept*/ { return Drink::Water; }
        static const/*expr*/ Drink max() /*noexcept*/ { return Drink::Juice; }
        static const/*expr*/ Drink lowest() /*noexcept*/ { return Drink::Water; }
        static const/*expr*/ Drink default() /*noexcept*/ { return Drink::Beer; }
    };
}
#pragma pop_macro("min")
#pragma pop_macro("max")

使用案例:

应用程序的变量:

Drink m_drink;

在构造函数中以:

初始化了哪个
m_drink = numeric_limits<Drink>::default();

关于表格的初始化,我可以做:

pComboDrink->SetCurSel(static_cast<int>(theApp.m_drink));

在其上,为了将接口调整到用户完成的更改中,我可以使用示波器枚举类值进行开关:

switch (static_cast<Drink>(pComboDrink->GetCurSel()))
{
case Drink::Water:
case Drink::Juice:
    pAlcohoolDegreesControl->Hide();
break;
case Drink::Beer:
case Drink::Wine:
    pAlcohoolDegreesControl->Show();
break;
default:
    break;
}

和对话框的确认过程(OnOK),我可以检查值是否超出边界,然后将其保存到相应的应用程序var:

int ix= pComboDrink->GetCurSel();
if (ix == -1)
    return FALSE;
#pragma push_macro("min")
#undef min
#pragma push_macro("max")
#undef max
if (ix < static_cast<int> (std::numeric_limits<Drink>::min()) ||  ix > static_cast<int> (std::numeric_limits<Drink>::max()) )
    return FALSE;
#pragma pop_macro("min")
#pragma pop_macro("max")
theApp.m_drink= static_cast<Drink>(ix);

注意:

  1. 关键字constexpr(我评论了/*expr*/,将其作为const)和noexcept的评论仅是因为我正在使用的编译器(Visual C 2013)在当前版本上不支持它们。
  2. 也许您不需要逻辑来临时不确定最小宏和最大宏。
  3. 我知道default()不适合"数字限制"范围;但这似乎是一个方便的地方。甚至它与default单词相吻合,在某些情况下是关键字!

不,没有,如果您需要的话,您可能不应该首先使用enum

在您的特殊情况下,您想致电Count的用例是什么?

afaik没有自动编译器支持的关键字可以获取enum中的总元素。OTOH通常没有意义:只要值不必具有结果值(即,您可以手动分配值,而不是依靠自动编号)。<<<<<<<<<<

一种常见的做法是通过以下方式声明enum

  typedef enum
    {
        Stopped, 
        Playing, 
        Paused,
        count
    }PossibleValues;  

这样,如果count始终是最后定义的 - 它将为您提供枚举元素的数量,假设编号从0开始,则是。

从类似问题(非序列整数C 枚举的最佳方法是什么是什么),因为它与其他几乎没有解决的问题有关。

您可以用来获得想要的模式是使用std :: prinitizer_list存储枚举的所有值。

namespace PossibleValues
{
    enum Type
    {
        ZERO= 0,
        PLUS180= 180,
        PLUS90= 90,
        MINUS90= -90
    };
    constexpr auto Values = {ZERO, PLUS180, PLUS90, MINUS90};
    size_t Count() { return Values.size(); }
    Type Default() { return *begin(Values); }
}

这也具有能够迭代枚举值的好处,即使它们没有线性值。

我认为您可以同时生成枚举,初始化器列表和带有变异宏的单个宏的功能,尽管在世界上最好的事情应该是标准。

编辑:当我将可能的价值用作枚举或使用struct作为可能的价值时,我的编译器会抱怨不完整的类型。为枚举使用名称空间有点不寻常,但效果很好。

可以改进来自https://stackoverflow.com/a/60216003/12894563的解决方案。我们可以在静态矢量中保存枚举表达式并迭代,获取最小/最大等等

用法:

#include <type_traits>
#include <algorithm>
#include <vector>
#include <iostream>
#define make_enum(Name, Type,  ...)                                              
    struct Name {                                                                
        enum : Type {                                                            
            __VA_ARGS__                                                          
        };                                                                       
        static auto count() { return values.size(); }                            
                                                                                 
        static inline const std::vector<Type> values = [] {                      
            static Type __VA_ARGS__; return std::vector<Type>({__VA_ARGS__});    
        }();                                                                     
        static Type min()                                                        
        {                                                                        
            static const Type result = *std::min_element(values.begin(), values.end()); 
            return result;                                                       
        }                                                                        
        static Type max()                                                        
        {                                                                        
            static const Type result = *std::max_element(values.begin(), values.end()); 
            return result;                                                       
        }                                                                        
}

make_enum(FakeEnum, int, A = 1, B = 0, C = 2, D);
int main(int argc, char *argv[])
{
    std::cout << FakeEnum::A     << std::endl
              << FakeEnum::min() << std::endl
              << FakeEnum::max() << std::endl
              << FakeEnum::count() << std::endl;
    return 0;
}

可能的类型可能是枚举?如果您只需要表现像枚举的事物,则可以执行以下操作:

#include <iostream>
#include <functional>
#include <set>

template <typename Representation, typename T>
class Iterable_Strong_Enum
{
private:
  struct T_Ptr_Less : public std::binary_function<T const *, T const *, bool>
  {
    bool operator()(T const * x, T const * y) const
    {
      return x->get_representation() < y->get_representation();
    }
  };
public:
  typedef std::set<T const *, T_Ptr_Less> instances_list;
  typedef typename instances_list::const_iterator const_iterator;
  Representation const & get_representation() const { return _value; }
  static Representation const & min() { return (*_instances.begin())->_value; }
  static Representation const & max() { return (*_instances.rbegin())->_value; }
  static T const * corresponding_enum(Representation const & value)
  {
    const_iterator it = std::find_if(_instances.begin(), _instances.end(), [&](T const * e) -> bool
    {
      return e->get_representation() == value;
    });
    if (it != _instances.end())
    {
      return *it;
    }
    else
    {
      return nullptr;
    }
  }
  bool operator==(T const & other) const { return _value == other._value; }
  bool operator!=(T const & other) const { return _value != other._value; }
  bool operator< (T const & other) const { return _value <  other._value; }
  bool operator<=(T const & other) const { return _value <= other._value; }
  bool operator> (T const & other) const { return _value >  other._value; }
  bool operator>=(T const & other) const { return _value >= other._value; }
  static bool is_valid_value(Representation const & value) { return corresponding_enum(value) != nullptr; }
  static typename instances_list::size_type size() { return _instances.size(); }
  static const_iterator begin() { return _instances.begin(); }
  static const_iterator end() { return _instances.end(); }
protected:
  explicit Iterable_Strong_Enum(Representation const & value);
private:
  Representation _value;
  static instances_list _instances;
};
template <typename Representation, typename T>
Iterable_Strong_Enum<Representation, T>::Iterable_Strong_Enum(Representation const & value)
: _value(value)
{
  _instances.insert(static_cast<T const *>(this));
}
class PossibleValues : public Iterable_Strong_Enum<int, PossibleValues>
{
public:
  static const PossibleValues Stopped;
  static const PossibleValues Playing;
  static const PossibleValues Pause;
protected:
private:
  explicit PossibleValues(int value);
};
PossibleValues::PossibleValues(int value) : Iterable_Strong_Enum<int, PossibleValues>(value) { }
// you need to call that explicitly
Iterable_Strong_Enum<int, PossibleValues>::instances_list Iterable_Strong_Enum<int, PossibleValues>::_instances;
const PossibleValues PossibleValues::Stopped(0);
const PossibleValues PossibleValues::Playing(1);
const PossibleValues PossibleValues::Pause(2);
void stackoverflow()
{
  std::cout << "There are " << PossibleValues::size() << " different possible values with representation: " << std::endl;
  for (auto pv = PossibleValues::begin(); pv != PossibleValues::end(); ++pv)
  {
    PossibleValues possible_value = **pv;
    std::cout << possible_value.get_representation() << std::endl;
  }
}

我对该解决方案有点撕裂。一方面,它非常普遍,另一方面是一个大问题。