I would like to pass a std::map
to chaiscript. However, I'm not sure how to do this. My code is currently as follows:
#include <map>
#include <string>
#include <chaiscript/chaiscript.hpp>
int main(int argc, char* argv[]) {
chaiscript::ChaiScript chai;
auto data = std::map<std::string, std::string>{
{ "key1", "val1"},
{ "key2", "val2"},
};
chai.add_global(chaiscript::var(&data), "data");
chai.eval(R"(
print(data["key1"]);
)");
}
However, this code crashes with an exception saying, that chaiscript doesn't know what to do with the bracket []
operator. How can I fix this?
I could tell chaiscript what the right function is, but I would prefer it, if the map is compatible with chaiscripts internal Map
type!
Update:
I found a bit in the documentation, which explains that the chaiscript map type supports arbitrary input. Looking at the code, this seems to be done by the Boxed_Value
type. However, this probably means that it is fundamentally impossible to directly insert std::map
into scripts.
I'm now thinking about either writing a custom type, or a conversion function to solve the problem. Keeping you posted...
As far as I can see, out-of-the-box-chaiscript only provides you with the std::map<std::string,chaiscript::Boxed_Value>
map type. Therefore, if you want to add your own map to a script, you need to either provide chaiscript with a new type, or convert to the given one. Thus, I see the following solutions:
Case 1: You only need to get out a map from chaiscript to c++
This case can be found in the documentation. You need to supply a conversion function, and off you go.
chai.add(chaiscript::map_conversion<std::map<std::string, std::string>>());
auto map = chai.boxed_cast<std::map<std::string, std::string>>(chai.eval("data"));
Case 2: You only need to supply a map to chaiscript from c++
This is basically the same as Case 1, but you have to supply the conversion function yourself.
auto convert = [](const std::map<std::string, std::string>& std_map) {
auto chai_map = std::map<std::string, chaiscript::Boxed_Value>{};
for (auto&& entry : std_map)
chai_map.emplace(entry.first, chaiscript::var(entry.second));
return chai_map;
};
chai.add(chaiscript::var(convert(data)),"data");
Case 3: You want to share a global value between chaiscript and c++
This case is rather tricky. You either have to supply chaiscript with a get_map() and send_map() function, which handle the data synchronization:
chai.eval(R"(
data = get_map();
data["key1"] = "val1";
send_map(data);
)");
Or you have to add a custom data type, which handles the synchronization in the background.
My Solution:
Fortunately for my case, I don't really need a shared state between chaiscript and c++, and therefore can rely on the solution for Case 2.