有一次,我曾考虑在C ++中实现一个类/模板,它将支持一个行为与Ada一样的Enum。自从我想到这个问题已经有一段时间了,我想知道是否有人解决了这个问题?
编辑:
道歉,我应该澄清一下我认为在Ena的Ada实现中有用的功能。鉴于枚举
type fruit is (apple, banana, cherry, peach, grape);
我们知道水果是列出的水果之一:苹果,香蕉,樱桃,桃子,葡萄。与C ++没什么不同。
在Ada的每个枚举中,您可以获得以下功能,而无需任何额外的工作:
我希望这可以更多地定义问题。
从评论添加的注释:
fruit'first
,它提供apple
。fruit'last
,它提供grape
。fruit'succ(apple)
,提供banana
。fruit'pred(cherry)
,也提供banana
。fruit'pos(cherry)
,返回2
,因为Ada使用从0开始的枚举。fruit'val(2)
,返回cherry
。fruit'Image(apple)
,它返回(大写)字符串"APPLE"
。fruit'Value("apple")
,返回值apple
。另见相关的SO问题:
答案 0 :(得分:3)
好的,让我们暂时离开C ++吧。 C ++只是C的超集(这意味着可以在C中完成的所有事情也可以在C ++中完成)。所以让我们专注于普通C(因为这是我熟悉的语言)。 C有枚举:
enum fruit { apple, banana, cherry, peach, grape };
这是完全合法的C,值是连续的,apple的值为零,banana的值为apple + 1.您可以创建带孔的枚举,但前提是明确打洞像这样
enum fruit { apple = 0, banana, cherry = 20, peach, grape };
当苹果为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");
这将打印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");
这将打印NO,myFruit的值与任何枚举常量不同。
顺便说一句,为了避免你必须说“enum fruit myFruit”,你可以避免使用typedef枚举。只需使用“typedef enum fruit fruit;”在自己的路上。现在你可以在前面没有枚举的情况下说“水果myFruit”。它通常在定义枚举时直接完成:typedef enum fruit { apple = 0, banana, cherry, peach, grape } fruit;
fruit myFruit;
缺点是你不再知道水果是一个枚举,它可能是一个物体,一个结构或其他任何东西。我通常会避免使用这些类型的typedef,如果一个enum和struct在前面,如果是一个struct(我会在这里使用它们,因为它看起来更好),我宁愿在前面编写枚举。
无法获取字符串值。在运行时,枚举只是一个数字。这意味着,如果你不知道什么样的枚举是不可能的(因为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;
}
输出:
banana
peach
I got called with fruit grape
这正是你想要的,还是我完全走错了路?
答案 1 :(得分:2)
答案 2 :(得分:1)
在C ++中没有一种简单的方法可以做到这一点,尤其是因为枚举常量不需要是唯一的或连续的。从值到字符串的转换也是非平凡的;我所知道的解决方案涉及C / C ++预处理器hackery - 这是对hackery一词的贬义用法。
我很想说“不”;我不确定这是否正确,但它肯定是非平凡的。
答案 3 :(得分:1)
你可以看看java enum(http://madbean.com/2004/mb2004-3/)和这个想法:http://en.wikipedia.org/wiki/Curiously_Recurring_Template_Pattern
答案 4 :(得分:1)
如果你对enumgen感兴趣,我做了一个简单的演示 你的榜样。如前所述,我使用它实现了它 常见的lisp,所以你写的输入文件是lispy,但我 我很难让语法合理化。
这是:
$ 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
要查看生成的代码,请访问以下网址: http://code.google.com/p/enumgen/source/browse/#svn/trunk/demo
尽管它的功能非常丰富,但它有很多东西 也可以通过在输入文件中设置变量来调整 或者通过指定枚举器的属性。
例如,默认情况下,它表示使用的字符串名称 std :: string,但它可以使用char const *或任何用户定义的字符串 上课了一点力气。
您可以将多个名称映射到相同的枚举值,但必须 选择一个作为“主要”,以便将值映射到字符串 将导致此名称(与其他名称相对。)
您可以明确地为枚举提供值,但它们不会 需要独一无二。 (重复项是前一个的隐式别名 具有相同值的枚举。)
此外,您可以迭代所有唯一值,并为每个值 所有别名的值,如果你愿意,这很有用 为这些生成脚本语言“包装器”,就像我们使用ruby一样。
如果您对使用此产品感兴趣并有疑问,请随时与我们联系 通过电子邮件联系我。 (gz的cuzdav)。
希望这会有所帮助。 (除了。之外没有很多文件 测试套件和演示代码,如果您关心它,请提供源代码。)
克里斯
答案 5 :(得分:1)
我使用Boost.Preprocessor编写了enum_iterator
和ENUM
宏一起编写了这个:
#include <iostream>
#include "enum.hpp"
ENUM(FooEnum,
(N)
(A = 1)
(B = 2)
(C = 4)
(D = 8));
int main() {
litb::enum_iterator< FooEnum, litb::SparseRange<FooEnum> > i = N, end;
while(i != end) {
std::cout << i.to_string() << ": " << *i << std::endl;
++i;
}
}
它将枚举声明为普通旧枚举,因此您仍可将其用于“正常”目的。迭代器也可用于具有顺序值的其他常规枚举,这就是为什么它有第二个模板参数,默认为litb::ConsequtiveRange<>
。它符合双向迭代器要求。
愚蠢的代码可以是downloaded from here
答案 6 :(得分:0)
This article向您展示了如何生成枚举值的字符串版本,尽管它要求您自己编写代码来编写代码。它还提供了一个预处理器宏,只要您的枚举是连续的,就可以非常轻松地允许递增和递减枚举变量。
This library提供更灵活的递增和递减。
Boost Vault中的enum_rev4.6.zip库提供了简单的字符串转换。看起来它支持使用迭代器递增和递减(这可能不太方便,但它可以工作)。它基本上没有文档,尽管libs / test目录包含一些很好的示例代码。
答案 7 :(得分:0)
这是未发布的软件,但似乎来自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/