热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

像Eum中的Enum一样使用C++中的Enum?-EnuminC++likeEnuminAda?

AtonepointIhadlookedatimplementingaclasstemplateinC++thatwouldsupportanEnumthatwo

At one point I had looked at implementing a class/template in C++ that would support an Enum that would behave like it does in Ada. It has been some time since I thought about this problem and I was wondering if anyone has ever solved this problem?

有一次,我曾考虑在C ++中实现一个类/模板,它将支持一个行为与Ada一样的Enum。自从我想到这个问题已经有一段时间了,我想知道是否有人解决了这个问题?

EDIT:

My apologies, I should clarify what functionality I thought were useful in the Ada implementation of the Enum. Given the enumeration

我道歉,我应该澄清一下我认为在Ena的Ada实现中有用的功能。鉴于列举

type fruit is (apple, banana, cherry, peach, grape);

We know that fruit is one of the listed fruits: apple, banana, cherry, peach, grape. Nothing really different there from C++.

我们知道水果是列出的水果之一:苹果,香蕉,樱桃,桃子,葡萄。与C ++没有什么不同。

What is very useful are the following pieces of functionality that you get with every enum in Ada without any additional work:

非常有用的是您在Ada中的每个枚举中获得的以下功能,而无需任何额外的工作:

  • printing out an enumerated value generates the string version
  • 打印出枚举值会生成字符串版本

  • you can increment the enumerated variable
  • 你可以增加枚举变量

  • you can decrement the enumerated variable
  • 你可以减少枚举变量

I hope this defines the problem a bit more.

我希望这可以更多地定义问题。


Notes added from comments:

注释中添加了注释:

  • See: Wikipedia (Judah Himango, 2008-11-19 at 0:09)
  • 见:维基百科(Judah Himango,2008-11-19 at 0:09)

  • See: Wikibooks

Useful features of Ada enumerations

  • The first value in the enumeration is fruit'first which gives apple.
  • 枚举中的第一个值是fruit'first,它给出了苹果。

  • The last value in the enumeration is fruit'last which gives grape.
  • 枚举中的最后一个值是fruit'last,它给出了葡萄。

  • The increment operation is fruit'succ(apple) which gives banana.
  • 增量操作是fruit'succ(apple),它给出了香蕉。

  • The decrement operation is fruit'pred(cherry) which also gives banana.
  • 减量操作是fruit'pred(樱桃),也给香蕉。

  • The conversion from enumeration to integer is fruit'pos(cherry) which returns 2 because Ada uses 0-based enumerations.
  • 从枚举到整数的转换是fruit'pos(cherry),它返回2,因为Ada使用从0开始的枚举。

  • The conversion from integer to enumeration is fruit'val(2) which returns cherry.
  • 从整数到枚举的转换是fruit'val(2),它返回cherry。

  • The conversion from enumeration to string is fruit'Image(apple) which returns the (upper-case) string "APPLE".
  • 从枚举到字符串的转换是fruit'Image(apple),它返回(大写)字符串“APPLE”。

  • The conversion from string to enumeration is fruit'Value("apple") which returns the value apple.
  • 从字符串到枚举的转换是fruit'Value(“apple”),它返回值apple。


See also related SO questions:

另见相关的SO问题:

  • Which Typesafe Enum in C++ Are You Using?
  • 您使用的是哪种C ++中的Typesafe枚举?

  • Next or previous enum
  • 下一个或上一个枚举

8 个解决方案

#1


3  

Okay, let's leave C++ aside for a moment. C++ is just a superset of C (which means everything that can be done in C can be done in C++ as well). So let's concentrate on plain-C (because that's a language I know well). C has enumerations:

好吧,让我们暂时离开C ++吧。 C ++只是C的超集(这意味着可以在C中完成的所有事情也可以在C ++中完成)。所以让我们专注于普通C(因为这是我熟悉的语言)。 C有枚举:

enum fruit { apple, banana, cherry, peach, grape };

This is perfectly legal C and the values are contiguous, and apple has the value zero and banana has the value apple + 1. You can create enumerations with holes, but only if you explicitly make holes like this

这是完全合法的C,值是连续的,apple的值为零,banana的值为apple + 1.您可以创建带孔的枚举,但前提是您明确地设置了这样的洞

enum  fruit { apple = 0, banana, cherry = 20, peach, grape };

While apple is 0 and banana is 1, cherry is 20, thus peach is 21 and grape is 22 and everything between 1 and 20 is undefined. Usually you don't want holes. You can do the following:

虽然苹果是0而香蕉是1,但是樱桃是20,因此桃子是21,葡萄是22,1到20之间的一切都是未定义的。通常你不想要洞。您可以执行以下操作:

enum fruit { apple = 0, banana, cherry, peach, grape };
enum fruit myFruit = banana;
myFruit++;
// myFruit is now cherry
printf("My fruit is cherry? %s\n", myFruit == cherry ? "YES" : "NO");

This will print YES. You can also do the following:

这将打印YES。您还可以执行以下操作:

enum fruit { apple = 0, banana, cherry = 20, peach, grape };
enum fruit myFruit = banana;
myFruit++;
// myFruit is now cherry
printf("My fruit is cherry? %s\n", myFruit == cherry ? "YES" : "NO");

This will print NO, and the value of myFruit is not the same as any of the enumeration constants.

这将打印NO,myFruit的值与任何枚举常量不同。

BTW, to avoid that you must say "enum fruit myFruit", you can avoid the enum with a typedef. Just use "typedef enum fruit fruit;" on an own line. Now you can say "fruit myFruit" without enum in front. It is often done directly when the enum is defined:

顺便说一句,为了避免你必须说“enum fruit myFruit”,你可以避免使用typedef枚举。只需使用“typedef enum fruit fruit;”在一条自己的路上。现在你可以在前面没有枚举的情况下说“水果myFruit”。通常在定义枚举时直接完成:

typedef enum fruit { apple = 0, banana, cherry, peach, grape } fruit;

fruit myFruit;

Disadvantage is that you don't know anymore that fruit is an enum, it might be an object, a structure or anything else. I usually avoid these type of typedefs, I rather write enum in front if an enum and struct in front if a struct (I will just use them here because it looks nicer).

缺点是你不再知道水果是一个枚举,它可能是一个物体,一个结构或其他任何东西。我通常会避免使用这种类型的typedef,如果一个结构中的枚举和结构,我宁愿在前面写枚举(我会在这里使用它们,因为它看起来更好)。

Getting the string value is not possible. At runtime an enumeration is just a number. That means, it's not possible if you don't know what kind of enumeration that is (as 0 might be apple, but it might also be a different thing of a different enumeration set). However, if you know it is a fruit, then it's easy to write a function that will do it for you. The preprocessor is your friend :-)

无法获取字符串值。在运行时,枚举只是一个数字。这意味着,如果你不知道那是什么类型的枚举是不可能的(因为0可能是苹果,但它也可能是不同枚举集的不同之处)。但是,如果你知道它是一种水果,那么编写一个可以为你做的功能很容易。预处理器是你的朋友:-)

typedef enum fruit {
    apple = 0,
    banana,
    cherry,
    peach,
    grape
} fruit;

#define STR_CASE(x) case x: return #x
const char * enum_fruit_to_string(fruit f) {
    switch (f) {
        STR_CASE(apple); STR_CASE(banana); STR_CASE(cherry);
        STR_CASE(peach); STR_CASE(grape);
    }
    return NULL;
}
#undef STR_CASE

static void testCall(fruit f) {
    // I have no idea what fruit will be passed to me, but I know it is
    // a fruit and I want to print the name at runtime
    printf("I got called with fruit %s\n", enum_fruit_to_string(f));
}

int main(int argc, char ** argv) {
    printf("%s\n", enum_fruit_to_string(banana));
    fruit myFruit = cherry;
    myFruit++; // myFruit is now peach
    printf("%s\n", enum_fruit_to_string(myFruit));
    // I can also pass an enumeration to a function
    testCall(grape);
    return 0;
}

Output:

banana
peach
I got called with fruit grape

This is exactly what you wanted or am I totally on the wrong track here?

这正是你想要的,还是我完全走错了?

#2


2  

One of my colleagues has implemented a tool to generate classes that do most (if not all) of what you want:

我的一位同事已经实现了一个工具来生成最能满足您需求的类(如果不是全部的话):

http://code.google.com/p/enumgen/

The current implementation is in Lisp, but do not hold that against him :-)

当前的实现是在Lisp中,但不要反对他:-)

#3


1  

There isn't an easy way to do that in C++, not least because the enumeration constants are not required to be unique or contiguous. The conversion from value to string is also non-trivial; the solutions I know of involve C/C++ Preprocessor hackery - and that is a pejorative use of the term hackery.

在C ++中没有一种简单的方法可以做到这一点,尤其是因为枚举常量不需要是唯一的或连续的。从值到字符串的转换也是非常重要的;我所知道的解决方案涉及C / C ++预处理器hackery - 这是对hackery一词的贬义用法。

I'm tempted to say "No"; I'm not certain that's correct, but it most certainly is non-trivial.

我很想说“不”;我不确定这是否正确,但它肯定是非平凡的。

#4


1  

you might take a look at the java enum (http://madbean.com/2004/mb2004-3/) and this idea: http://en.wikipedia.org/wiki/Curiously_Recurring_Template_Pattern

你可以看看java enum(http://madbean.com/2004/mb2004-3/)和这个想法:http://en.wikipedia.org/wiki/Curiously_Recurring_Template_Pattern

#5


1  

If you're interested in enumgen, I made a simple demo with your example. As already mentioned, I implemented it using common lisp, so the input file you write is lispy, but I tried really hard to make the syntax reasonable.

如果你对enumgen感兴趣,我用你的例子做了一个简单的演示。正如已经提到的,我使用常见的lisp实现它,所以你编写的输入文件是lispy,但我努力使语法合理。

Here it is:

这里是:

$ cat Fruit.enum
(def-enum "Fruit" (("apple")
                   ("banana")
                   ("cherry")
                   ("peach")
                   ("grape")
                   ("INVALID_")))

$ enumgen Fruit.enum
Using clisp
;; Loading file /tmp/enumgen/enumgen.lisp ...
;; Loaded file /tmp/enumgen/enumgen.lisp
loading def file:
;; Loading file /tmp/enumgen/enumgen.def ...
;; Loaded file /tmp/enumgen/enumgen.def
generating output:
  Fruit.cpp
  Fruit.ipp
  Fruit.hpp
DONE

To view the generated code, visit this url: http://code.google.com/p/enumgen/source/browse/#svn/trunk/demo

要查看生成的代码,请访问以下网址:http://code.google.com/p/enumgen/source/browse/#svn/trunk/demo

While it's pretty feature-rich as it is, there are a lot of things that can be tweaked as well, by setting variables in the input file or by specifying attributes of the enumerators.

虽然它的功能非常丰富,但通过在输入文件中设置变量或指定枚举器的属性,还可以调整很多东西。

For example, by default it represents the string names using std::string, but it can use char const * or any user-defined string class given a little effort.

例如,默认情况下,它使用std :: string表示字符串名称,但它可以使用char const *或任何用户定义的字符串类,只需花费一点力气。

You can have multiple names map to the same enum value, but must pick one to be the "primary" such that mapping the value to a string will result in this name (as opposed to the others.)

您可以将多个名称映射到相同的枚举值,但必须选择一个作为“主要”,以便将值映射到字符串将导致此名称(与其他名称相对)。

You can explicitly provide values to the enums, and they do not need to be unique. (Duplicates are implicit aliases for the previous enum with the same value.)

您可以明确地为枚举提供值,并且它们不必是唯一的。 (重复项是前一个枚举的隐含别名,具有相同的值。)

Further, you can iterate over all the unique values, and for each value over all its aliases, which is useful if you want to generate script-language "wrappers" for these, like we do using ruby.

此外,您可以遍历所有唯一值,并遍历其所有别名中的每个值,如果您要为这些值生成脚本语言“包装器”,这非常有用,就像我们使用ruby一样。

If you're interested in using this and have questions, feel free to contact me via email. (cuzdav at gmail).

如果您对使用此产品感兴趣并有疑问,请随时通过电子邮件与我联系。 (gz的cuzdav)。

Hope this helps. (There isn't a lot of documentation aside from the test suite and demo code, and the source if you care about that.)

希望这可以帮助。 (除了测试套件和演示代码之外,没有很多文档,如果你关心它,还有源代码。)

Chris

#6


1  

I wrote an enum_iterator that does this, together with a ENUM macro using Boost.Preprocessor:

我写了一个使用Boost.Preprocessor执行此操作的enum_iterator以及一个ENUM宏:

#include 
#include "enum.hpp"

ENUM(FooEnum, 
  (N)
  (A = 1)
  (B = 2)
  (C = 4)
  (D = 8));

int main() {
  litb::enum_iterator > i = N, end;
  while(i != end) {
    std::cout <

It declares the enum as plain old enum, so you may still use it for "normal" purposes. The iterator can be used for other normal enums too that have sequential values, that's why it has a second template parameter which defaults to litb::ConsequtiveRange<>. It conforms to the bidirectional iterator requirements.

它将枚举声明为普通的枚举,因此您仍可将其用于“正常”目的。迭代器也可用于具有顺序值的其他常规枚举,这就是为什么它有第二个模板参数,默认为litb :: ConsequtiveRange <>。它符合双向迭代器要求。

The silly code can be downloaded from here

愚蠢的代码可以从这里下载

#7


0  

This article shows you how to generate the string version of an enumerated value, although it requires that you write the code to do so yourself. It also provides a preprocessor macro to very easily permit incrementing and decrementing enumerated variables, as long as your enum is continuous.

本文将向您展示如何生成枚举值的字符串版本,尽管它需要您自己编写代码来编写代码。它还提供了一个预处理器宏,只要您的枚举是连续的,就可以非常轻松地允许递增和递减枚举变量。

This library provides more flexible incrementing and decrementing.

该库提供更灵活的递增和递减。

The enum_rev4.6.zip library in the Boost Vault provides easy string conversions. It looks like it supports incrementing and decrementing using iterators (which is probably less convenient, but it works). It's basically undocumented, although the libs/test directory contains some good example code.

Boost Vault中的enum_rev4.6.zip库提供了简单的字符串转换。看起来它支持使用迭代器递增和递减(这可能不太方便,但它可以工作)。它基本上没有文档,尽管libs / test目录包含一些很好的示例代码。

#8


0  

It's unreleased software but it seems BOOST_ENUM from Frank Laub could fit the bill. The part I like about it is that you can define an enum within the scope of a class which most of the Macro based enums usually don't let you do. It is located in the Boost Vault at: http://www.boostpro.com/vault/index.php?action=downloadfile&filename=enum_rev4.6.zip&directory=& It hasn't seen any development since 2006 so I don't know how well it compiles with the new Boost releases. Look under libs/test for an example of usage. There is also Boost smart_enum (not released either). It does the iterator part of your question but not the output to a string. http://cryp.to/smart-enum/

它是未发布的软件,但似乎来自Frank Laub的BOOST_ENUM可以满足要求。我喜欢它的部分是你可以在一个类的范围内定义一个枚举,大多数基于宏的枚举通常不允许你这样做。它位于Boost Vault中:http://www.boostpro.com/vault/index.php?action = downloadfile&filename = enum_rev4.6.zip&directory =&它自2006年以来没有任何发展,所以我没有知道它如何与新的Boost版本一起编译。在libs / test下查看用法示例。还有Boost smart_enum(未发布)。它执行问题的迭代器部分,但不输出字符串。 http://cryp.to/smart-enum/


推荐阅读
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • IjustinheritedsomewebpageswhichusesMooTools.IneverusedMooTools.NowIneedtoaddsomef ... [详细]
  • 本文讨论了微软的STL容器类是否线程安全。根据MSDN的回答,STL容器类包括vector、deque、list、queue、stack、priority_queue、valarray、map、hash_map、multimap、hash_multimap、set、hash_set、multiset、hash_multiset、basic_string和bitset。对于单个对象来说,多个线程同时读取是安全的。但如果一个线程正在写入一个对象,那么所有的读写操作都需要进行同步。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • This article discusses the efficiency of using char str[] and char *str and whether there is any reason to prefer one over the other. It explains the difference between the two and provides an example to illustrate their usage. ... [详细]
  • 本文详细介绍了git常用命令及其操作方法,包括查看、添加、提交、删除、找回等操作,以及如何重置修改文件、抛弃工作区修改、将工作文件提交到本地暂存区、从版本库中删除文件等。同时还介绍了如何从暂存区恢复到工作文件、恢复最近一次提交过的状态,以及如何合并多个操作等。 ... [详细]
  • 本文介绍了使用哈夫曼树实现文件压缩和解压的方法。首先对数据结构课程设计中的代码进行了分析,包括使用时间调用、常量定义和统计文件中各个字符时相关的结构体。然后讨论了哈夫曼树的实现原理和算法。最后介绍了文件压缩和解压的具体步骤,包括字符统计、构建哈夫曼树、生成编码表、编码和解码过程。通过实例演示了文件压缩和解压的效果。本文的内容对于理解哈夫曼树的实现原理和应用具有一定的参考价值。 ... [详细]
  • Postgresql备份和恢复的方法及命令行操作步骤
    本文介绍了使用Postgresql进行备份和恢复的方法及命令行操作步骤。通过使用pg_dump命令进行备份,pg_restore命令进行恢复,并设置-h localhost选项,可以完成数据的备份和恢复操作。此外,本文还提供了参考链接以获取更多详细信息。 ... [详细]
  • 使用圣杯布局模式实现网站首页的内容布局
    本文介绍了使用圣杯布局模式实现网站首页的内容布局的方法,包括HTML部分代码和实例。同时还提供了公司新闻、最新产品、关于我们、联系我们等页面的布局示例。商品展示区包括了车里子和农家生态土鸡蛋等产品的价格信息。 ... [详细]
author-avatar
LordHo
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有