在 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_mapthe 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,