2012-01-27 7 views
8

Używam SWIG 2.0 do tworzenia wrapperów Pythona dla biblioteki C++. Jedna metoda ma argument typu "const std :: map &". SWIG szczęśliwie generuje dla niego opakowanie, ale nie wiem, jak wywołać tę metodę. Jeśli przejdę, na przykład, {"a": "b"} dla tego argumentu, otrzymam komunikat "NotImplementedError: Wrong number or type of arguments for overloaded function".W jaki sposób SWIG zawija mapę <string, string> w języku Python?

Spojrzałem na wygenerowany plik .cxx w nadziei, że to wyjaśni, ale tak się nie stało. Oto kod, który przetwarza ten 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 &""'"); 
} 

Bez wątpienia wie, że argument istnieje, i że jest to coś, co przekształca się w mapę. Ale nie mogę zrozumieć, co naprawdę chce, żebym się na to zgodził.

+0

W pliku swig do was wyraźnie owinąć mapę? Myślę, że musisz utworzyć zmienną typu wypełnienia, wywołując wstawkę z kodu Pythona. – mark

Odpowiedz

16

Kiedy używasz C++ szablonu (np std::map<string, string>) trzeba utworzyć alias dla niego w pliku .i więc można go użyć w Pythonie:

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

Teraz powiedzmy chcesz owinąć funkcję, która wygląda tak:

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

na stronie Pythona, trzeba zdać map_string_string foo, a nie dict Python. Okazuje się, że można łatwo przekonwertować dict Pythona na mapie chociaż robiąc to:

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

więc jeśli chcesz zadzwonić foo, trzeba to zrobić:

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

Oto pełna przykładów kod, który działa.

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

%} 

I pyton kodu testu:

#run_test.py 
import test 

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

A moja linia poleceń:

% 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 
+0

To nie działa dla mnie: map_string_string ({'a': 'b'}) powoduje dokładnie taki sam błąd jak {'a': 'b'}. Zhakowałem wygenerowany kod C++, aby uzyskać więcej informacji o tym, co się dzieje, i nie ma to dla mnie żadnego sensu. Chociaż przekazuję dict (lub map_string_string) do metody Pythona, PyObject, który jest przekazywany dla odpowiedniego argumentu, to krotka zawierająca tylko klucze. Wartości nie wydają się być przekazywane gdziekolwiek. – peastman

+0

Dodałem szczegółowy przykład. Wypróbuj to. –

+0

Ups, moja wina. (A raczej wina osoby, która pierwotnie stworzyła kod SWIG.) Okazuje się, że był kod przetwarzający wszystkie argumenty, i to właśnie zmieniło dyktaturę w krotkę. – peastman

Powiązane problemy