简体   繁体   中英

Store multiple types as values in C++ dictionary?

I want to write a C++ object that behaves almost equivalent to a Python dictionary. C++'s std::map and std::unordered_map accommodate some of the functionalities that Python dictionaries already have, yet lack one of the most important capabilities, namely, being able to add arbitrary objects and types. Even if it isn't possible, how close can you get to achieving the capabilities of Python's dictionary?

A few previous questions ( here and here ) fail to handle the issue of adding multiple types to the dictionary.

For example, I want to be able to do something like this in C++:

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

The best solutions that I can think would be like using void pointers to data which get reinterpreted, or perhaps some kind of run-time polymorphism with some type restrictions?

The best solutions that I can think would be like using void pointers to data which get reinterpreted , or perhaps some kind of run-time polymorphism with some type restrictions?

Many void pointers and many reinterpretation of pointers in modern C++ should be a signal of a bad design, in my opinion. I believe that polymorphism would be a way to go.

Also, if you have a fixed number of types you want to use, consider using C++17's std::any or std::variant which is a more modern 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
        );
    }

}

The above example might be useful in some use-cases.

Also check out how json objects are implemented in any C++ json library. It might be helpful.

Edit: I added an example of std::visit that iterates over keys in our dictionary.

I was looking for a similar solution for hard coding the parameters of my python experiments into c++ . I found the std'17 variant module very useful.

#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;
}

The result:

Airplanes
/media/m_result/
5
0.5
number five

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM