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

发布于 2024-08-19 02:49:31 字数 459 浏览 7 评论 0原文

我想到了这个问题

enum Folders {FA, FB, FC};

当我有类似的想法并想为每个文件夹创建一个容器数组时,

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

:(使用映射更优雅: std::mapm_containers;

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

This question came to my mind, when I had something like

enum Folders {FA, FB, FC};

and wanted to create an array of containers for each folder:

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

(Using maps it's much more elegant to use: std::map<Folders, ContainerClass*> m_containers;)

But to come back to my original question: What if I do not want to hard-code the array size, is there a way to figure out how many items are in Folders? (Without relying on e.g. FC being the last item in the list which would allow something like ContainerClass*m_containers[FC+1] if I'm not mistaken.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

贩梦商人 2024-08-26 02:49:31

确实没有一个好的方法来做到这一点,通常你会在枚举中看到一个额外的项目,即

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

那么你可以这样做:

int fuz[FOOBAR_NR_ITEMS];

不过仍然不是很好。

但当然,您确实意识到,仅枚举中的项目数并不安全,例如

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

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

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

There's not really a good way to do this, usually you see an extra item in the enum, i.e.

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

So then you can do:

int fuz[FOOBAR_NR_ITEMS];

Still not very nice though.

But of course you do realize that just the number of items in an enum is not safe, given e.g.

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

the number of items would be 4, but the integer values of the enum values would be way out of the array index range. Using enum values for array indexing is not safe, you should consider other options.

edit: as requested, made the special entry stick out more.

江湖正好 2024-08-26 02:49:31

对于 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 包含有用的警告,例如以下代码的“枚举值未包含在 switch 中”。让Folders_MAX == FC + 1 会打破这些警告,因为你最终会得到一堆永远不应该包含在 switch 中的 ...MAX 枚举值。
switch (folder) 
{
  case FA: ...;
  case FB: ...;
  // Oops, forgot FC!
}

For C++, there are various type-safe enum techniques available, and some of those (such as the proposed-but-never-submitted Boost.Enum) include support for getting the size of a enum.

The simplest approach, which works in C as well as C++, is to adopt a convention of declaring a ...MAX value for each of your enum types:

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

Edit: Regarding { FA, FB, FC, Folders_MAX = FC} versus {FA, FB, FC, Folders_MAX]: I prefer setting the ...MAX value to the last legal value of the enum for a few reasons:

  1. The constant's name is technically more accurate (since Folders_MAX gives the maximum possible enum value).
  2. Personally, I feel like Folders_MAX = FC stands out from other entries out a bit more (making it a bit harder to accidentally add enum values without updating the max value, a problem Martin York referenced).
  3. GCC includes helpful warnings like "enumeration value not included in switch" for code such as the following. Letting Folders_MAX == FC + 1 breaks those warnings, since you end up with a bunch of ...MAX enumeration values that should never be included in switch.
switch (folder) 
{
  case FA: ...;
  case FB: ...;
  // Oops, forgot FC!
}
冷默言语 2024-08-26 02:49:31

以 STL 的方式来说,特质怎么样?例如:

enum Foo
{
    Bar,
    Baz
};

编写一个

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

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

How about traits, in an STL fashion? For instance:

enum Foo
{
    Bar,
    Baz
};

write an

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

specialization (possibly constexpr if you use c++11). Then, in your test code provide any static assertions to maintain the constraints that std::numeric_limits::max() = last_item.

不忘初心 2024-08-26 02:49:31

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

ContainerClass* m_containers[Folders_MAX];

Add a entry, at the end of your enum, called Folders_MAX or something similar and use this value when initializing your arrays.

ContainerClass* m_containers[Folders_MAX];
世界等同你 2024-08-26 02:49:31

我确实没有看到任何方法可以真正获取 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 个项目的数组

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

I really do not see any way to really get to the number of values in an enumeration in C++. Any of the before mention solution work as long as you do not define the value of your enumerations if you define you value that you might run into situations where you either create arrays too big or too small

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

in this about examples the result would create a array of 3 items when you need an array of 5 items

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

in this about examples the result would create a array of 301 items when you need an array of 5 items

The best way to solve this problem in the general case would be to iterate through your enumerations but that is not in the standard yet as far as I know

缱倦旧时光 2024-08-26 02:49:31

我喜欢使用枚举作为函数的参数。这是提供固定“选项”列表的简单方法。这里投票最高的答案的问题在于,使用它,客户端可以指定“无效选项”。作为衍生,我建议做本质上相同的事情,但在枚举之外使用常量 int 来定义它们的计数。

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

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

I like to use enums as arguments to my functions. It's an easy means to provide a fixed list of "options". The trouble with the top voted answer here is that using that, a client can specify an "invalid option". As a spin off, I recommend doing essentially the same thing, but use a constant int outside of the enum to define the count of them.

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

It's not pleasant, but it's a clean solution if you don't change the enum without updating the constant.

两仪 2024-08-26 02:49:31

这是在编译时执行此操作的最佳方法。我使用了此处的 arg_var count 答案。

#define PP_NARG(...) \
     PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
#define PP_NARG_(...) \
         PP_ARG_N(__VA_ARGS__)

#define PP_ARG_N( \
          _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
         _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
         _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
         _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
         _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
         _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
         _61,_62,_63,N,...) N
#define PP_RSEQ_N() \
         63,62,61,60,                   \
         59,58,57,56,55,54,53,52,51,50, \
         49,48,47,46,45,44,43,42,41,40, \
         39,38,37,36,35,34,33,32,31,30, \
         29,28,27,26,25,24,23,22,21,20, \
         19,18,17,16,15,14,13,12,11,10, \
         9,8,7,6,5,4,3,2,1,0

#define TypedEnum(Name, ...)                                      \
struct Name {                                                     \
    enum {                                                        \
        __VA_ARGS__                                               \
    };                                                            \
    static const uint32_t Name##_MAX = PP_NARG(__VA_ARGS__);      \
}

#define Enum(Name, ...) TypedEnum(Name, __VA_ARGS__)

要声明枚举:

Enum(TestEnum, 
Enum_1= 0,
Enum_2= 1,
Enum_3= 2,
Enum_4= 4,
Enum_5= 8,
Enum_6= 16,
Enum_7= 32);

最大值将在此处可用:

int array [TestEnum::TestEnum_MAX];
for(uint32_t fIdx = 0; fIdx < TestEnum::TestEnum_MAX; fIdx++)
{
     array [fIdx] = 0;
}

Here is the best way to do it in compilation time. I have used the arg_var count answer from here.

#define PP_NARG(...) \
     PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
#define PP_NARG_(...) \
         PP_ARG_N(__VA_ARGS__)

#define PP_ARG_N( \
          _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
         _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
         _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
         _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
         _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
         _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
         _61,_62,_63,N,...) N
#define PP_RSEQ_N() \
         63,62,61,60,                   \
         59,58,57,56,55,54,53,52,51,50, \
         49,48,47,46,45,44,43,42,41,40, \
         39,38,37,36,35,34,33,32,31,30, \
         29,28,27,26,25,24,23,22,21,20, \
         19,18,17,16,15,14,13,12,11,10, \
         9,8,7,6,5,4,3,2,1,0

#define TypedEnum(Name, ...)                                      \
struct Name {                                                     \
    enum {                                                        \
        __VA_ARGS__                                               \
    };                                                            \
    static const uint32_t Name##_MAX = PP_NARG(__VA_ARGS__);      \
}

#define Enum(Name, ...) TypedEnum(Name, __VA_ARGS__)

To declare an enum:

Enum(TestEnum, 
Enum_1= 0,
Enum_2= 1,
Enum_3= 2,
Enum_4= 4,
Enum_5= 8,
Enum_6= 16,
Enum_7= 32);

the max will be available here:

int array [TestEnum::TestEnum_MAX];
for(uint32_t fIdx = 0; fIdx < TestEnum::TestEnum_MAX; fIdx++)
{
     array [fIdx] = 0;
}
审判长 2024-08-26 02:49:31

与@wich答案类似,但稍微干净一些:

enum class Fruit:int {  // Assumes there are no gaps in the enum
    Apple = 0, 
    Banana,
    Orange,
    LAST_ENTRY_OF_ENUM
};

constexpr int FruitLastEntry = static_cast<int>(Fruit::LAST_ENTRY_OF_ENUM);

int stocksOfFruit[FruitLastEntry];

使用更现代的 constexpr 和 static_cast 来获取易于使用的 int 值,该值可用于数组大小等。 。

该名称明确指出它是 LAST ENTRY 而不是 SIZE,以确保这没有暗示它是防弹 SIZE 值,并且仅当枚举是连续的并且编号中没有间隙时才可以使用它

可使用的 Godbolt 链接:https://godbolt.org/z/7eKadd7T5

Similar to @wich answer, but slightly cleaner:

enum class Fruit:int {  // Assumes there are no gaps in the enum
    Apple = 0, 
    Banana,
    Orange,
    LAST_ENTRY_OF_ENUM
};

constexpr int FruitLastEntry = static_cast<int>(Fruit::LAST_ENTRY_OF_ENUM);

int stocksOfFruit[FruitLastEntry];

Using more modern constexpr and static_cast to get easy-to-use int value which can be used for array sizes, etc...

The name explicitly states that it's the LAST ENTRY and not SIZE, to ensure this doesn't have an implied meaning that it's bulletproof SIZE value and that it can be used only when the enum is sequential and there are no gaps in the numbering.

Godbolt link to play with: https://godbolt.org/z/7eKadd7T5

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文