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?
One can only put one type of object into a dictionary. If one wants to put a variety of types of data into the same dictionary, e.g. for configuration information or other common data stores, the superclass of all possible held data types must be used to define the dictionary.
In python, if we want a dictionary in which one key has multiple values, then we need to associate an object with each key as value. This value object should be capable of having various values inside it. We can either use a tuple or a list as a value in the dictionary to associate multiple values with a key.
Note: If you have multiple values acting as the key, you would define a class to encapsulate those values and provide proper overrides of GetHashCode and Equals so that the dictionary could recognize their equality.
You can use a Dictionary<string,object> and then you can put anything you want into it.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With