将enum和string组合成一个类似map的变量,可以同时用于int和string
C++ Combine enum and string into a map-like variable, able to be used with both int and string
假设我有一个enum
:
enum Types
{
TYPE_ASCENDING,
TYPE_DESCENDING
};
,我用它来…代码中的任何地方。比如if(bla < TYPE_ASCENDING)
,或者是switch/case
。实际的enum
要大得多。
无论检查结果(或其他任何结果)如何,它都需要以更美观的方式为std::cout
,以便让用户知道发生了什么。那么,继续if()
的例子,它可能是这样的:
if(bla < TYPE_ASCENDING)
std::cout << "Ascending.n";
所有这些都发生在类中。我的问题:是否有一种方法来定义某种类型的变量/STL/任何允许存储enum
和std::string
类变量的东西,但也让我单独使用这两种类型?
一个想法是namespace
,但它似乎不能在类中使用。为了举例说明,下面是它的样子:
namespace Type
{
enum Types
{
ASCENDING,
DESCENDING
};
std::string s[2] {"Ascending", "Descending"};
};
,对于if()
,它被称为Type::ASCENDING
,对于字符串,它被称为Type::s[0]
。但是,在类中没有namespace
,所以这不是一个解决方案。
使用std::map
只允许我使用int
作为索引,所以我只能使用这个:
std::map<Types, std::string> m {{TYPE_ASCENDING, "Ascending}, {TYPE_DESCENDING, "Descending"}};
作为m[0]
或m[TYPE_ASCENDING]
,但我不能调用它,因为它的索引要在if()
中使用。为此,我必须单独调用enum
,这意味着我有enum
和map
两个变量。我需要一个统一的变量名,以避免在代码中追逐变量名。
如果我使用struct
,我不能直接访问Struct::TYPE_DESENDING
,我需要创建一个对象。
我可以使用enum
和std::string
数组/向量,但这意味着,再次,我必须分别调用两个变量,我希望它们是统一的。
我想要的可能吗?
在原生c++中并没有这种机制。你可以写一个map/mapper函数
enum class E
{
ONE,
TWO
};
std::unordered_map<E,std::string> eStrings { {E::ONE,"ONE"},{E::TWO,"two"}};
虽然这是c++ 11,但您可以对旧版本的c++做同样的操作
你可以这样写
std::cout << eStrings[E::ONE];
这里的问题是您必须手动维护它。因此,当向枚举中添加新值时,必须手动向映射中添加新条目。
对于编写具有此行为的类或函数也是如此。您总是必须复制枚举声明的代码和到字符串的映射。
这里的一个解决方案是使用一些工具来生成这些
你可以在一些文件中定义你的enum(这只是一些随机的格式,只是为了解释这一点)。在您自己的定义文件中选择您想要的任何内容)
E
- ONE
- TWO
然后在头文件和/或cpp文件中生成c++枚举和Map。
enum class <name>
{
<foreach:> <value>,
};
std::unordered_map< <name> ,std::string> eStrings
{
<foreach:> {<name>::<value>,"<value>"},
};
如果你不喜欢使用映射,这种方法是非常灵活的。如果愿意,还可以生成一个switch case语句
std::string getString(<name> e)
{
switch(e)
{
<foreach:> case <name>::<value>: return "<value>";
}
}
这里的语法没有任何标准,只是一些"伪代码"来可视化这个概念。有几种方法可以生成c++代码。你可以选择任何你想要的,或者编写自己的程序。
注意:
这也是一个一般的概念。你可以将这个功能/映射等包装到另一个类中,使其静态等进行优化,而不是将其放在全局作用域中。
如果你需要比查找字符串的映射更花哨的东西,你可以用这个概念创建一个类,或者另一个只做反向查找的映射。更重要的是,您很可能不得不使用外部工具生成代码。
阅读Hayts的回答我看到我最初写的可能与自动生成代码方面有关。所以我把它留在这里。
看到常规的旧enum
可以隐式地转换为int
(而不是enum classes
),您可以简单地使用map<int, string>
。
现在,到有趣的部分,半自动生成它。
#include <iostream>
#include <map>
#include <string>
struct Thing {
enum Type {
# define ENUM_DEF(v, s) v,
ENUM_DEF(TYPE_ASCENDING, "Ascending")
ENUM_DEF(TYPE_DESCENDING, "Descending")
# undef ENUM_DEF
};
std::map<int, std::string> string;
Thing() {
# define ENUM_DEF(v, s) string[v] = s;
ENUM_DEF(TYPE_ASCENDING, "Ascending")
ENUM_DEF(TYPE_DESCENDING, "Descending")
# undef ENUM_DEF
}
};
int main() {
Thing t;
std::cout << t.string[0];
return 0;
}
我使用了一种称为x -宏的技术。前提是将枚举所需的所有参数传递给宏。然后根据需要如何使用参数来定义宏。首先:
# define ENUM_DEF(v, s) v,
这只是将enum标记扩展为常规enum定义。
然后,在Thing
中c'tor:
# define ENUM_DEF(v, s) string[v] = s;
展开为填充映射所需的语句。
最后一点,你可能有问题:你真的要做所有这些重复,重新输入ENUM_DEF
所有的时间?
幸运的是,你不知道。你可以把这些语句移动到它们自己的文件中,我们把它命名为type_enum.def
:
#ifdef ENUM_DEF
ENUM_DEF(TYPE_ASCENDING, "Ascending")
ENUM_DEF(TYPE_DESCENDING, "Descending")
#endif //ENUM_DEF
原来的代码变成:
#include <iostream>
#include <map>
#include <string>
struct Thing {
enum Type {
# define ENUM_DEF(v, s) v,
# include "type_enum.def"
# undef ENUM_DEF
};
std::map<int, std::string> string;
Thing() {
# define ENUM_DEF(v, s) string[v] = s;
# include "type_enum.def"
# undef ENUM_DEF
}
};
int main() {
Thing t;
std::cout << t.string[0];
return 0;
}
- 如果我注释掉换行符,为什么'string'会成为一个不合格的变量
- GDB 8.1 无法在单线程简单程序中跟踪 std::string 变量的值
- 为什么当我使用 std::string::operator[] 时自动变量不会成为引用?
- 使用词法强制转换在'string to double'中设置双精度变量的精度
- 检查 std::any 变量是否包含 std::string 时出现问题
- 变量参数列表 后面的'const std::string&'弄乱了堆栈
- 变量具有不完整的类型std :: String;string.h有很多错误
- 如何有效地将底层数据从 std::string 移动到其他类型的变量?
- 如何在系统( "say string variable" )中使用字符串变量?
- 初始化 std::string& 的私有类变量
- 在 std::string 变量中使用提升库存储文件名
- C SEG故障在STD :: String Destructor上,仅当传递变量时
- 围绕变量[String]的堆叠为损坏的C
- c++如何打印另一种类型的变量的String属性的值
- 如何获取字符串形式的int变量的长度内置函数,例如string.length()
- 从包含表示约 64 GB 值的十进制数的 String 变量中获取值
- 您是否需要析构函数来销毁全局 int、float 或 std::string 变量
- GCC如何连接多个c++ std::string变量
- 输入Std::cin与直接赋值Std::string变量不一样
- Cout在声明一个std::string变量后不给出任何输出