(如何)我可以计算枚举中的项目?


98

当我有类似的东西时,我想到了这个问题

enum Folders {FA, FB, FC};

并希望为每个文件夹创建一个容器数组:

ContainerClass*m_containers[3];
....
m_containers[FA] = ...; // etc.

(使用地图这是更优雅的使用方法:std::map<Folders, ContainerClass*> m_containers;

但是回到我的原始问题:如果我不想对数组大小进行硬编码怎么办,有没有办法确定文件夹中有多少个项目?(无需依赖于例如FC列表中的最后一项,ContainerClass*m_containers[FC+1]如果我没有记错的话,这将允许类似的操作。)



1
这个问题有点不足。根据C ++标准,int(FA) | int(FB) | int (FC)也是Folders变量的合法值。如果您要调整大小m_containers以使任何Folders变量都是有效索引,[FC+1]那么大小将不够。
MSalters 2011年


Answers:


123

这样做确实不是一个好方法,通常您会在枚举中看到一个额外的项,即

enum foobar {foo, bar, baz, quz, FOOBAR_NR_ITEMS};

因此,您可以执行以下操作:

int fuz[FOOBAR_NR_ITEMS];

仍然不是很好。

但是,当然,您会意识到,枚举中的枚举项数量并不安全,例如

enum foobar {foo, bar = 5, baz, quz = 20};

项目数将为4,但枚举值的整数值将超出数组索引范围。将枚举值用于数组索引并不安全,应考虑其他选择。

编辑:根据要求,使特殊条目更加突出。


27
称其为LAST或ALWAYS_AT_END或不太神秘的名称。让它伸出来。这样,后续的维护人员就不会在结束标记后意外添加新条目。
马丁·约克

3
无论好坏,这都是我们组织所采用的方法。我们通常将其称为FINAL_enumname_ENTRY,例如FINAL_foobar_ENTRY。我还看到人们在枚举声明后立即使用一个单独的静态const FOOBAR_COUNT变量,这种方法更容易出错。
Darryl 2010年

1
至少很容易看到“ enum foo {a = 10,LAST}”会很奇怪。而且我认为在这种情况下,“ int arr [LAST]”将是11个项目,而不是2个,因此大多数代码都可以工作(但是您在无效的索引值上浪费了内存)
代码憎恶者

32

对于C ++,有多种类型安全的枚举技术可用,其中一些(例如,建议但从未提交的Boost.Enum)包括对获取枚举大小的支持。

在C和C ++中都起作用的最简单方法是采用一种约定,为每种枚举类型声明... MAX值:

enum Folders { FA, FB, FC, Folders_MAX = FC };
ContainerClass *m_containers[Folders_MAX + 1];
....
m_containers[FA] = ...; // etc.

编辑:关于{ FA, FB, FC, Folders_MAX = FC}{FA, FB, FC, Folders_MAX]:我喜欢... MAX值设置为枚举几个原因的最后一个合法值:

  1. 该常量的名称在技术上更准确(因为Folders_MAX给出了最大可能的枚举值)。
  2. 就我个人而言,我觉得自己Folders_MAX = FC比其他条目更具优势(这使得在不更新最大值的情况下意外添加枚举值变得更加困难,这是Martin York提到的问题)。
  3. 对于以下代码,GCC包括一些有用的警告,例如“开关中未包含枚举值”。让Folders_MAX == FC + 1会破坏这些警告,因为最终会产生一堆... MAX枚举值,这些值永远不应包含在开关中。
开关(文件夹) 
{
  案例FA:...;
  情况FB:...;
  //糟糕,忘了FC!
}

3
为什么不enum Folders { FA, FB, FC, Folders_MAX }; ContainerClass *m_containers[Folders_MAX];呢?
比尔2010年

1
我更想表明最后一个是数字,并且由于以下原因,它们都具有相同的名称:struct SomeEnum { enum type {FA, FB, FC, NB__};};
卢克·赫米特

2
实际上,我觉得这些“有益的”警告是对的。我喜欢在开发时总是设置-Wall -pedantic等好的警告,但是这些警告只是愚蠢的。只会出现一些更糟的情况,例如为&& ||建议括号 和&^ | 运算符优先级。我的意思是,我认为Java是保姆的语言,这到底是发生在C和C ++ ...
至极

2
使用Folders_max = FC的缺点是,每次向枚举添加一些东西时都必须更改它!
艾蒂安

2
枚举Folders {FA,FB,FC,Folders_MIN = FA,Folders_MAX = FC};只是强调它对迭代有用吗?
gjpc 2015年

7

STL方式的特征如何?例如:

enum Foo
{
    Bar,
    Baz
};

写一个

std::numeric_limits<enum Foo>::max()

专业化(如果使用c ++ 11,则可能为constexpr)。然后,在测试代码中提供任何静态断言来维护std :: numeric_limits :: max()= last_item的约束。


2
不幸的是,这将无法按照此答案
rr-

3
std::numeric_limits<enum Foo>::max()总是返回零...(请参见链接答案的问题)在gum 5.2.0 @ Linux和MinGW 4.9.3 @ Windows 上对普通枚举(enum Foo { ... }),类型提示的枚举(enum class Foo : uint8_t { ... })进行测试。
rr-

1
(...,如果为std::numeric_limits<std::underlying_type<Foo>::type>::max(),则返回基础类型的最大值,即32位整数为0xFFFFFFFF,在这种情况下没有用。)
rr

1
奇怪,因为我有执行我所描述的代码。namespace gx { enum struct DnaNucleobase : char { A, C, G, T }; } 然后:namespace std { template<> struct numeric_limits<enum ::gx::DnaNucleobase> { typedef enum ::gx::DnaNucleobase value_type; static constexpr value_type max() { return value_type::T; } (...) std::cout << std::numeric_limits<::gx::DnaNucleobase>::max() << std::endl;打印预期结果。经gcc 5.2.1和4.8 / 4.9口味测试。
Wojciech Migda,2015年

2
-1; 如果您更改答案,请ping我,这样我就可以撤消downvote。这个答案是不好遵循的约定。这是对概念的滥用numeric_limits<T>::max()。函数唯一可以合理返回的是最高枚举值。它会返回2,但是OP(在这种情况下)将需要它返回3。一旦有了枚举(FB = 2057)的非默认值,所有的赌注都将关闭,甚至+ 1无法破解一个一的错误。如果有numeric_limits<T>::number_of_elements_of_the_set()(或简称),则可以毫无歧义地使用。
Merlyn Morgan-Graham

3

在枚举末尾添加一个名为Folders_MAX或类似名称的条目,并在初始化数组时使用此值。

ContainerClass* m_containers[Folders_MAX];

2

我喜欢将枚举用作函数的参数。提供固定的“选项”列表是一种简便的方法。投票结果最高的问题在于,使用该选项,客户可以指定“无效选项”。作为衍生产品,我建议做基本相同的事情,但是在枚举外部使用一个常量int来定义它们的数量。

enum foobar { foo, bar, baz, quz };
const int FOOBAR_NR_ITEMS=4;

这并不令人愉快,但是如果您不更新常量而不更改枚举,则这是一个干净的解决方案。


1

我真的看不到有什么方法可以真正达到C ++枚举中的值数量。只要您不定义枚举的值(如果定义值),任何前面提到的解决方案都可以工作,否则可能会遇到创建太大或太小的数组的情况

enum example{ test1 = -2, test2 = -1, test3 = 0, test4 = 1, test5 = 2 }

在本示例中,当您需要5个项目的数组时,结果将创建3个项目的数组

enum example2{ test1 , test2 , test3 , test4 , test5 = 301 }

在本示例中,当您需要5个项目的数组时,结果将创建301个项目的数组

一般情况下,解决此问题的最佳方法是遍历您的枚举,但据我所知这还不是标准

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.