【问题标题】:Store multiple types as values in C++ dictionary?将多种类型作为值存储在 C++ 字典中?
【发布时间】:2019-10-14 11:52:32
【问题描述】:

我想编写一个行为几乎等同于 Python 字典的 C++ 对象。 C++ 的std::mapstd::unordered_map 提供了Python 字典已经具备的一些功能,但缺少最重要的功能之一,即能够添加任意对象和类型。即使不可能,你离实现 Python 字典的功能还有多远?

之前的几个问题(herehere)未能处理向字典中添加多种类型的问题。

例如,我希望能够在 C++ 中做这样的事情:

my_dict = {'first': 1,
           'second': "string",
           'third': 3.5,
           'fourth': my_object}
my_dict['fifth'] = list([1, 2, 3])

我能想到的最佳解决方案是使用 void 指向重新解释的数据的指针,或者可能是具有某些类型限制的某种运行时多态性?

【问题讨论】:

  • @CalebGoodman 我真的不这么认为。该操作询问是否插入任意类型的元素。
  • 坦率地说,在 Python 容器中使用异构类型虽然绝对有可能,但我认为这不是“最重要的功能”之一。事实上,我会说在容器中使用异构类型几乎总是糟糕的设计。
  • 相关:C++ std::map holding ANY type of value(涵盖值)。
  • 也相关:Different key type in a map。这表明它可以通过提升来实现,而在没有提升的情况下做到这一点(至少在提出问题时)更加有限。不知道 C++17 的添加(例如 std::variant/std::any)是否有帮助。

标签: python c++


【解决方案1】:

我能想到的最好的解决方案是使用 void 指向重新解释的数据的指针,或者可能是具有某些类型限制的某种运行时多态性?

在我看来,现代 C++ 中许多 void 指针和指针的许多重新解释应该是糟糕设计的信号。我相信多态性将是一种方法。

此外,如果您要使用固定数量的类型,请考虑使用 C++17 的 std::anystd::variant,后者是更现代的 union

#include <iostream>
#include <map>
#include <string>
#include <variant>

typedef std::map<std::variant<int, std::string>, std::variant<int, std::string>> Dict;

int main(){
    Dict d;
    d["key"] = 1;
    d[5] = "woah";
    std::cout << std::get<int>(d["key"]) << std::endl; // prints 1

    // edit: print all the keys in d
    for(auto& k_v: d){
        std::visit(
            [](auto& value){std::cout << value << ' ';},
            k_v.first // k_v.second to print all values in d
        );
    }

}

上面的示例在某些用例中可能很有用。

还可以查看 json 对象是如何在任何 C++ json 库中实现的。这可能会有所帮助。

编辑:我添加了一个 std::visit 的示例,它遍历我们字典中的键。

【讨论】:

  • 另外,不要这样做。希望始终知道您需要使用的值的接口。
  • 不要这样做是什么意思?首先使用这种多类型字典不是一个好主意,所以如果 don't do this 是根据它,我同意。
  • 你能添加一个简短的例子来展示如何使用std::visit吗?这是std::variant 的首选接口,而且它通常比调用std::get 更容易使用
【解决方案2】:

我正在寻找一种类似的解决方案,将我的 python 实验的参数硬编码到 c++ 中。我发现std'17 variant 模块非常有用。

#include <iostream>
#include <map>
#include <variant>
#include <vector>
#include <string>

int main(){
    typedef std::map<std::variant<std::string, int>, std::variant<int, double, float, std::string>> Dict;

    std::vector<Dict> params = {
        {
            {"label", "Labs"},
            {"dir", "/media/sf_Data/"},
            {"num_frames", 4},
            {"scale_factor", 1.0},
            {5, "my number five"},
        }, // Dict 0
        {
            {"label", "Airplanes"},
            {"dir", "/media/m_result/"},
            {"num_frames", 5},
            {"scale_factor", 0.5},
            {5, "number five"},
        } // Dict 1
    };

    int idx = 1;
    std::string label   = std::get<std::string>(params[idx]["label"]);
    std::string folder  = std::get<std::string>(params[idx]["dir"]);
    int num_frames      = std::get<int>(params[idx]["num_frames"]);
    double scf          = std::get<double>(params[idx]["scale_factor"]);
    std::string nbstr   = std::get<std::string>(params[idx][5]);
    
    std::cout << label << std::endl;
    std::cout << folder << std::endl;
    std::cout << num_frames << std::endl;
    std::cout << scf << std::endl;
    std::cout << nbstr << std::endl;

    return 0;
}

结果:

Airplanes
/media/m_result/
5
0.5
number five

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-09
    • 2014-03-29
    • 2019-03-10
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多