在 C++ 中制作动态文本可寻址列表
Making a dynamically text-addressable list in C++
在大多数脚本语言中,对象通常是项目的集合,绑定到这些对象中的名称。例如(在 Javascript 中),如果我要初始化这个:
colors = {
Blue: 0x0000FF; //Hex Values
Green: 0x00FF00;
Red: 0xFF0000;
}
在运行时,如果用户输入了列出的颜色,我可以使用 colors["given_color"]
.
轻松 return 相应的十六进制值
但是,我将如何用 C++ 或其他编译语言来表达一个非常相似的机制?创建一个 enum
只会静态地有意义,在一个人为的例子中:
public enum colors{
CYAN = 0x00FFFF,
MAGENTA = 0xFF00FF,
YELLOW = 0xFFFF00
}
不能以任何方式用于查找 say std::cin << givenColor;
的相应十六进制
也就是说,我有什么选择可以将 std::string
转换为数据点、指针或函数指针?
您要查找的数据结构称为 map (or a dictionary or associative array). In C++, there's std::map
which is always sorted (generally implemented as a red-black tree), and std::unordered_map
which is generally faster because it uses a hash table(但内容是任意顺序的)。
std::unordered_map<std::string, int> colors = {
{"blue", 0x0000FF},
{"green", 0x00FF00},
{"red", 0xFF0000}
};
std::string key = /* something */;
std::string value = colors[key];
回复评论中的问题:是的,你可以在地图中存储任何你想要的东西。唯一的限制是对于 std::unordered_map
、the key type needs implement a hash function and operator==
和 std::map
,密钥类型需要实现 operator<
。值类型可以是任何类型。
您可以使用 std::unordered_map
:
#include <unordered_map>
#include <string>
int main() {
std::unordered_map<std::string, unsigned int> colors =
{
{"CYAN", 0x00FFFF},
{"MAGENTA", 0xFF00FF},
{"YELLOW", 0xFFFF00},
};
unsigned int retrieved_color = colors["CYAN"];
}
现在,如果您尝试将 C++ 用作 JavaScript 之类的动态语言,我会有点困扰。如果你真的需要映射一个字符串,你从你无法控制的地方得到,也许你从网络收到,或者类似的东西,这很好。这是要走的路。
但如果您只需要能够在代码中使用名称 CYAN
,则将此解决方案与 enum
进行比较:
obj.set_color(CYAN);
对比
obj.set_color(colors["CYAN"]);
第一个在编译时解析,set_color
接收一个文字常量作为参数。
第二种,文字串"CYAN"
用于初始化临时对象std::string
,然后复制到堆分配的地方。然后计算该字符串的哈希值(O(N),我相信在字符串的大小中,Java 在制作字符串哈希值时仅使用几个字符就已经出现问题),然后进行一次内存提取得到实际值。最后临时 std::string
被释放。然后调用函数set_color
。
这笔额外费用与您的计划无关吗?可能是。但最终,有多少不相关的额外成本会堆积在您的最终产品中?
将 C++ 的高效与重载运算符 << 的轻松调试结合起来,像这样:
enum class colors {
CYAN = 0x00FFFF,
MAGENTA = 0xFF00FF,
YELLOW = 0xFFFF00
};
std::ostream& operator<<(std::ostream& os, colors c)
{
switch(c) {
case colors::CYAN : os << "cyan"; break;
case colors::MAGENTA : os << "magenta"; break;
case colors::YELLOW : os << "yellow"; break;
}
return os;
}
BOOST_AUTO_TEST_CASE(play_colors)
{
std::vector<colors> v { colors::CYAN, colors::YELLOW, colors::MAGENTA };
std::copy(begin(v), end(v), ostream_iterator<colors>(cout, ", "));
cout << endl;
}
预期输出(添加正确的 headers 后):
cyan, yellow, magenta,
在大多数脚本语言中,对象通常是项目的集合,绑定到这些对象中的名称。例如(在 Javascript 中),如果我要初始化这个:
colors = {
Blue: 0x0000FF; //Hex Values
Green: 0x00FF00;
Red: 0xFF0000;
}
在运行时,如果用户输入了列出的颜色,我可以使用 colors["given_color"]
.
但是,我将如何用 C++ 或其他编译语言来表达一个非常相似的机制?创建一个 enum
只会静态地有意义,在一个人为的例子中:
public enum colors{
CYAN = 0x00FFFF,
MAGENTA = 0xFF00FF,
YELLOW = 0xFFFF00
}
不能以任何方式用于查找 say std::cin << givenColor;
也就是说,我有什么选择可以将 std::string
转换为数据点、指针或函数指针?
您要查找的数据结构称为 map (or a dictionary or associative array). In C++, there's std::map
which is always sorted (generally implemented as a red-black tree), and std::unordered_map
which is generally faster because it uses a hash table(但内容是任意顺序的)。
std::unordered_map<std::string, int> colors = {
{"blue", 0x0000FF},
{"green", 0x00FF00},
{"red", 0xFF0000}
};
std::string key = /* something */;
std::string value = colors[key];
回复评论中的问题:是的,你可以在地图中存储任何你想要的东西。唯一的限制是对于 std::unordered_map
、the key type needs implement a hash function and operator==
和 std::map
,密钥类型需要实现 operator<
。值类型可以是任何类型。
您可以使用 std::unordered_map
:
#include <unordered_map>
#include <string>
int main() {
std::unordered_map<std::string, unsigned int> colors =
{
{"CYAN", 0x00FFFF},
{"MAGENTA", 0xFF00FF},
{"YELLOW", 0xFFFF00},
};
unsigned int retrieved_color = colors["CYAN"];
}
现在,如果您尝试将 C++ 用作 JavaScript 之类的动态语言,我会有点困扰。如果你真的需要映射一个字符串,你从你无法控制的地方得到,也许你从网络收到,或者类似的东西,这很好。这是要走的路。
但如果您只需要能够在代码中使用名称 CYAN
,则将此解决方案与 enum
进行比较:
obj.set_color(CYAN);
对比
obj.set_color(colors["CYAN"]);
第一个在编译时解析,set_color
接收一个文字常量作为参数。
第二种,文字串"CYAN"
用于初始化临时对象std::string
,然后复制到堆分配的地方。然后计算该字符串的哈希值(O(N),我相信在字符串的大小中,Java 在制作字符串哈希值时仅使用几个字符就已经出现问题),然后进行一次内存提取得到实际值。最后临时 std::string
被释放。然后调用函数set_color
。
这笔额外费用与您的计划无关吗?可能是。但最终,有多少不相关的额外成本会堆积在您的最终产品中?
将 C++ 的高效与重载运算符 << 的轻松调试结合起来,像这样:
enum class colors {
CYAN = 0x00FFFF,
MAGENTA = 0xFF00FF,
YELLOW = 0xFFFF00
};
std::ostream& operator<<(std::ostream& os, colors c)
{
switch(c) {
case colors::CYAN : os << "cyan"; break;
case colors::MAGENTA : os << "magenta"; break;
case colors::YELLOW : os << "yellow"; break;
}
return os;
}
BOOST_AUTO_TEST_CASE(play_colors)
{
std::vector<colors> v { colors::CYAN, colors::YELLOW, colors::MAGENTA };
std::copy(begin(v), end(v), ostream_iterator<colors>(cout, ", "));
cout << endl;
}
预期输出(添加正确的 headers 后):
cyan, yellow, magenta,