2012-01-27 16 views
8

Sto usando SWIG 2.0 per creare un wrapper Python per una libreria C++. Un metodo ha un argomento di tipo "const std :: map &". SWIG genera felicemente un wrapper per questo, ma non riesco a capire come richiamare il metodo. Se passo, ad esempio, {"a": "b"} per quell'argomento, ottengo un errore "NotImplementedError: Wrong number or type of argument overloaded".In che modo SWIG avvolge una mappa <stringa, stringa> in Python?

Ho guardato il file .cxx generato nella speranza che avrebbe chiarito, ma non è stato così. Ecco il codice che elabora tale argomento:

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 &""'"); 
} 

Si sa chiaramente esiste tale argomento, e che si suppone di essere qualcosa che viene convertito in una mappa. Ma non riesco a capire cosa voglia effettivamente passare per questo.

+0

Nel file sorso a te avvolgere in modo esplicito la mappa? Penso che sia necessario creare una variabile del tipo the populate chiamando insert dal codice python. – mark

risposta

16

Quando si utilizza un C++ modello (ad esempio, un std::map<string, string>) è necessario creare un alias per esso nel file .i in modo da poter usare in python:

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

Ora diciamo che si desidera avvolgere una funzione che assomiglia a questo:

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

Sul lato pitone, è necessario passare un map_string_string a foo, non un dict pitone. Si scopre che è possibile convertire facilmente un dict pitone a una mappa anche se in questo modo:

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

quindi se si desidera chiamare foo, è necessario fare questo:

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

Ecco completo esempio codice che funziona.

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

%} 

E il codice di prova python:

#run_test.py 
import test 

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

E la mia linea di comando:

% 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

Questo non funziona per me: map_string_string ({'a': 'b'}) produce esattamente lo stesso errore di {'a': 'b'}. Ho hackerato il codice C++ generato per ottenere maggiori informazioni su cosa sta succedendo, e non ha alcun senso per me. Sebbene io passi un dict (o map_string_string) al metodo Python, il PyObject che viene passato per l'argomento corrispondente è una tupla contenente solo le chiavi. I valori non sembrano essere passati da nessuna parte. – peastman

+0

Ho aggiunto un esempio dettagliato. Provalo. –

+0

Oops, colpa mia. (O piuttosto, la colpa della persona che ha originariamente creato il codice SWIG.) Si scopre che c'era del codice che pre-elaborava tutti gli argomenti, ed è quello che stava trasformando il dict in una tupla. – peastman

Problemi correlati