C++实现enum转字符串,支持enum的指定值语法

C/C++的enum,无法直接转换到字符串,比如 enum FRUIT {apple, grape=10, orange};,永远只有0、10、11,无法得到能直观理解的“appl”、“grape”、“orange”了。Java语言就能在打印枚举值时打印出字符串。

cout  << FRUIT(10) 我们希望输出的是grape,而不是10

直到C++2020标准都出台了,也没听说C/C++给出标准解决方案。而这个需求其实一直非常强烈。

常见的解决方案:

1)做一个class,它有一个operator int()成员函数,然后定义若干这个class的全局变量冒充枚举。缺点就是,在模板编程的时候,可能因为模板会阻止类型间转换动作而导致这个对象可能无法正确转换到int

2)幅度修改定义枚举的语法,实现了夹带私货的动作

#define FOREACH_FRUIT(FRUIT, OP) \
    FRUIT(apple) \
    FRUIT(orange OP(apple)) \
    FRUIT(grape) \
    FRUIT(banana OP(0xFFFF))

enum FRUIT_ENUM {FOREACH_FRUIT(GENERATE_ENUM, ASSIGN)};

struct {int value; const char * name;} FRUIT_ENUM_VALUE_TO_NAME[] = {FOREACH_FRUIT(GENERATE_STRING, EQUAL)};

3) 尽可能接近enum语法,定义一个真实enum。但是,很难支持grape=10这样的指定值语法。

这里给出一个可以解决这个困难的方案,要点是使用optional甩开=前面的部分,而大家一般是是试图甩开=后面的部分,导致无解:

  1. #define SEMOICOLON() ;
  2. #define TO_ENUM_VALUE_NAME(a) [](){\
  3.    std::optional<int> x, a;\
  4.    x=a;\
  5.    if (x)\
  6.    {\
  7.       v.emplace_back(*x, #a);\
  8.    }\
  9.    else if (v.empty())\
  10.    {\
  11.         v.emplace_back(0, #a);\
  12.    }\
  13.    else\
  14.    {\
  15.       v.emplace_back(v.back().first + 1, #a);\
  16.    }\
  17. }()
  18.     
  19. #define ENUM(EnumName, ...) enum EnumName {__VA_ARGS__};\
  20.     inline string to_string(EnumName x)\
  21.     {\
  22.         static vector<pair<int, string>> v;\
  23.         static bool inited = [](){\
  24.             FOR_EACH(TO_ENUM_VALUE_NAME, SEMOICOLON, __VA_ARGS__);\
  25.             return true;\
  26.         }();\
  27.         static map<int, string>      EnumName##_StrMap;\
  28.         auto iter = EnumName##_StrMap.find(x);\
  29.         if (iter == EnumName##_StrMap.end())\
  30.         {\
  31.             std::tie(iter, std::ignore) = EnumName##_StrMap.emplace(x, to_string(int(x)) + "(" + #EnumName + ":"+ algorithm::join(v | adaptors::filtered([x](auto & a){return a.first == int(x);}) | adaptors::map_values, "/") + ")");\
  32.         }\
  33.         return iter->second;\
  34.     }
  35. ENUM(FRUIT, apple, grape = apple + 1, orange = 10, banana=orange);

不定参数宏的遍历,网上很多讲解,要点就是使用PP_NARG宏,所以FOR_EACH宏部分就留给大家作为作业了

最终效果:

  1.  cout << apple << " " << grape << " " << orange << endl;
  2.     cout << to_string(FRUIT(0)) << endl;    
  3.     cout << to_string(grape) << endl;
  4.     cout << to_string(FRUIT(10)) << endl;

  输出:

  1. 0 1 10
  2. 0(FRUIT:apple)
  3. 1(FRUIT:grape = apple + 1)
  4. 10(FRUIT:orange = 10/banana=orange
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C语言中,枚举类型和字符串之间的互相换是比较常见的需求。下面将分别介绍如何实现这两种换。 首先,将枚举类型换成字符串。在C语言中,我们可以利用switch语句和枚举类型的取实现。如下面的代码所示: ```c enum Fruit { APPLE, BANANA, ORANGE }; const char* fruitToString(enum Fruit fruit) { switch (fruit) { case APPLE: return "apple"; case BANANA: return "banana"; case ORANGE: return "orange"; default: return ""; } } ``` 在这段代码中,我们定义了一个枚举类型`Fruit`,其中包含了三个取。然后,我们定义了一个函数`fruitToString`,该函数接受一个枚举类型的参数,并返回一个对应的字符串。在函数内部,我们使用了switch语句来根据不同的枚举返回不同的字符串。 其次,将字符串换成枚举类型。在C语言中,我们可以采用一些方法来实现这个换。以下是一种常见的方式: ```c enum Fruit stringToFruit(const char* str) { if (strcmp(str, "apple") == 0) { return APPLE; } else if (strcmp(str, "banana") == 0) { return BANANA; } else if (strcmp(str, "orange") == 0) { return ORANGE; } else { return -1; // 表示换失败 } } ``` 在这个函数中,我们定义了一个名为`stringToFruit`的函数,该函数将一个字符串换成枚举类型。我们使用了`strcmp`函数来比较字符串是否相等,从而确定对应的枚举。如果字符串无法换成枚举类型,函数返回-1表示换失败。 总的来说,在C语言中,枚举类型和字符串互相换并不是很复杂。只要我们熟悉基本的语法和函数,就可以很轻松地实现这些换。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值