How does SWIG wrap a <string, string> map in Python?

I am using SWIG 2.0 to create a Python wrapper for the C ++ library. One method has an argument like "const std :: map &". SWIG happily creates a wrapper for it, but I cannot figure out how to call this method. If I pass, for example, {"a": "b"} for this argument, I get the error "NotImplementedError: Wrong number or type of arguments for overloaded function".

I looked at the generated .cxx file in the hope that this will clear up, but it is not. Here is the code handling this argument:

res4 = SWIG_ConvertPtr(obj3, &argp4, SWIGTYPE_p_std__mapT_std__string_std__string_t, 0 | 0); if (!SWIG_IsOK(res4)) { SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "new_Context" "', argument " "4"" of type '" "std::map< std::string,std::string > const &""'"); } 

He clearly knows that there is an argument, and that it must be something that transforms into a map. But I can’t understand what he really wants to convey to me.

+8
c ++ python stl swig
source share
1 answer

When you use a C ++ template (e.g. std::map<string, string> ), you need to create an alias for it in your .i file so that you can use it in python:

 namespace std { %template(map_string_string) map<string, string>; } 

Now suppose you want to wrap a function that looks like this:

 void foo(const std::map<string, string> &arg); 

On the python side, you need to pass map_string_string to foo, not a python dict. Turns out you can easily convert python python to a map, but in doing so:

 map_string_string({ 'a' : 'b' }) 

so if you want to call foo you need to do this:

 foo(map_string_string({ 'a' : 'b' })) 

Here is a complete example of code that works.

 // test.i %module test %include "std_string.i" %include "std_map.i" namespace std { %template(map_string_string) map<string, string>; } void foo(const std::map<std::string, std::string> &val); %{ #include <iostream> #include <string> #include <map> using namespace std; void foo(const map<string, string> &val) { map<string, string>::const_iterator i = val.begin(); map<string, string>::const_iterator end = val.end(); while (i != end) { cout << i->first << " : " << i->second << endl; ++i; } } %} 

And python test code:

 #run_test.py import test x = test.map_string_string({ 'a' : 'b', 'c' : 'd' }) test.foo(x) 

And my command line is:

 % swig -python -c++ test.i % g++ -fPIC -shared -I/usr/include/python2.7 -o _test.so test_wrap.cxx % python run_test.py a : b c : d 
+16
source share

All Articles