【问题标题】:Accessing a nested dictionary unordered_map<string, void*> in c++?在 C++ 中访问嵌套字典 unordered_map<string, void*>?
【发布时间】:2017-12-02 05:19:46
【问题描述】:

假设我们提供了一个嵌套字典,其中的值要么是字符串,要么是另一个字典,声明为:

unordered_map&lt;string, void*&gt; dictionary

我们如何使用这个字典访问和执行操作?

【问题讨论】:

  • 您如何知道void* 是指向字符串还是字典?还是这就是问题的根源?
  • void* 转换为包含字符串或其他字典的自定义类型,您可以查询它有哪些。
  • 此信息在问题中提供给我们。
  • 查看en.cppreference.com/w/cpp/container/unordered_mapcplusplus.com/reference/unordered_map/unordered_map。但是为什么不使用map,它应该可以通过二分搜索更快地读取(写入map 比写入unordered_map 慢,因为map 寻找插入新值的好地方,而unordered_dict 只是附加它,但需要更多时间阅读)。

标签: c++ c++11 dictionary void-pointers unordered-map


【解决方案1】:

您可能希望使用variant 类型而不是void* 指针。

所以像这样声明无序映射

struct Map {
    std::unordered_map<
        std::string, 
        std::variant<std::unique_ptr<Map>, std::string>
    > mp;
};  

然后像这样使用它

auto map = Map{};
// insert another map for the key "something"
map.mp["something"] = std::make_unique<Map>();
// insert a string for the key "else"
map.mp["else"] = "whatever";

然后使用这样的映射(使用 C++17),其中 operator&lt;&lt;Map 类型重载

// gotta love structured bindings <3
for (const auto& [key, value] : map) {
    std::visit(value, [&key](auto& value) { 
        cout << key << " : " << value << endl;
    }
}

或使用 C++14

for (const auto& key_value : map) {
    std::visit(value, [&key_value](auto& value) {
        cout << key_value.first << " : " << value << endl;
    }
}

如果你没有 C++17 的访问权限,那么你仍然可以使用变体的独立实现,例如 boost::variant 等。逻辑和代码看起来惊人的相似


如果由于某种原因给你一个指向 void* 的指针,而你绝对不能更改 API,你可以使用以下最小可行的解决方案

struct StringOrAnother {
    enum class Type { STRING, MAP };
    Type type;
    std::unordered_map<std::string, void*> mp;
    std::string str;
};

auto mp = std::unordered_map<std::string, void*> mp;

// insert a string
auto val_one = new StringOrAnother{STRING};
val_one.str = "some value";
mp["key one"] = &val_one;
auto val_two = new StringOrAnother{MAP};
mp["key two"] = &val_two;

void print(const std::unordered_map<std::string, void*>& mp) {

    for (const auto& key_value : mp) {
        cout << key_value.first << " : ";
        auto& value = *static_cast<StringOrAnother*>(&key_value.second);
        if (value.second.type == StringOrAnother::STRING) {
            cout << value.second.str << endl;
        } else {
            print(value.second.mp);
        }
    }

}

请注意,我没有使用unique_ptr 作为指针,而是手动分配了它们。稍后由您来delete 他们而不是泄漏内存!

【讨论】:

  • any 也是一个好主意(用于类型安全访问)。 en.cppreference.com/w/cpp/utility/any
  • 应该补充一点 std::variant 是 C++17 的一部分(OP 的问题是关于 C++11)
  • 如果你知道它是两种类型中的一种,any 似乎相当严厉。
  • @AlexanderHuszagh 我不认为any 适合这种情况。如果在编译时知道类型列表,那么std::variant 效率会高很多
  • @BishalGautam 如果你坚持使用void*,那就这样吧,但要知道,在现实世界中,你应该使用void* 的唯一时候是你正在与另一个库交互这要求您提供void*。在 C++ 程序中使用void* 是设计不佳的标志。像瘟疫一样避免它。
猜你喜欢
  • 2021-11-09
  • 2012-07-26
  • 1970-01-01
  • 2013-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-06
  • 2018-02-07
相关资源
最近更新 更多