计数枚举C 自动
Count on enum C++ automatic
在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);
注意:
- 关键字
constexpr
(我评论了/*expr*/
,将其作为const
)和noexcept
的评论仅是因为我正在使用的编译器(Visual C 2013)在当前版本上不支持它们。 - 也许您不需要逻辑来临时不确定最小宏和最大宏。
- 我知道
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;
}
}
我对该解决方案有点撕裂。一方面,它非常普遍,另一方面是一个大问题。
- 不带大括号的枚举形式
- 枚举环境变量的惯用C++14/C++17方法
- 类似枚举的计算常量
- 如何正确实现和访问运算符的各种自定义枚举器
- 错误:从"int"到枚举c++的转换无效
- C++中构造函数中的枚举
- 访问在 C++ 结构中声明的枚举变量
- 枚举类'classname'的多重定义
- 强枚举类型定义:Clang Bug 还是 C++11 标准不确定性?
- typedef 枚举和枚举类有什么区别?
- 为什么我的开关/机箱在使用枚举时默认?
- 传递 C++11 枚举类作为模板,同时自动推断其类型
- 计数枚举C 自动
- 自动为枚举添加类似 Java 枚举的功能
- 自动生成枚举查找表
- 映射/联接两个自动生成的枚举的最佳方式
- 在结构中自动索引枚举ID
- 如何自动将强类型枚举转换为整型
- 枚举用于多个文件,或多个文件的自动唯一常量
- 自动创建从整数到枚举的值映射