2012-01-27 31 views
8

Tôi đang sử dụng SWIG 2.0 để tạo trình bao bọc Python cho thư viện C++. Một phương thức có đối số thuộc loại "const std :: map &". SWIG vui vẻ tạo ra một wrapper cho nó, nhưng tôi không thể tìm ra cách để gọi phương thức. Nếu tôi vượt qua, ví dụ, {"a": "b"} cho đối số đó, tôi nhận được một lỗi "NotImplementedError: Sai số hoặc loại đối số cho hàm quá tải".SWIG quấn một bản đồ <string, string> bằng Python như thế nào?

Tôi đã xem tệp .cxx được tạo với hy vọng nó sẽ làm rõ, nhưng không. Đây là mã xử lý đối số đó:

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

Rõ ràng là đối số tồn tại và nó được coi là thứ được chuyển đổi thành bản đồ. Nhưng tôi không thể hiểu được nó thực sự muốn tôi vượt qua nó.

+0

Trong tập uống một lân của bạn với bạn một cách rõ ràng quấn bản đồ? Tôi nghĩ rằng bạn cần phải tạo một biến của các loại dân cư bằng cách gọi chèn từ bên trong mã python. – mark

Trả lời

16

Khi bạn đang sử dụng C++ template (ví dụ như một std::map<string, string>), bạn cần phải tạo ra một bí danh cho nó trong tập tin .i để bạn có thể sử dụng nó trong python:

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

Bây giờ giả sử bạn muốn bọc một chức năng trông như thế này:

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

Ở phía trăn, bạn cần chuyển một map_string_string đến foo, không phải là một dict python. Nó chỉ ra rằng bạn có thể dễ dàng chuyển đổi một dict python để bản đồ mặc dù bằng cách làm này:

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

vì vậy nếu bạn muốn gọi foo, bạn cần phải làm điều này:

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

Dưới đây là ví dụ hoàn mã hoạt động.

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

%} 

Và mã kiểm tra python:

#run_test.py 
import test 

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

Và dòng lệnh của tôi:

% 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

Điều này không hiệu quả đối với tôi: map_string_string ({'a': 'b'}) tạo ra chính xác lỗi giống như {'a': 'b'}. Tôi đã hack mã C++ được tạo ra để có thêm thông tin về những gì đang diễn ra, và nó không có ý nghĩa gì đối với tôi. Mặc dù tôi đang chuyển một dict (hoặc map_string_string) đến phương thức Python, PyObject được truyền cho đối số tương ứng là một bộ chứa chỉ các khóa. Các giá trị dường như không được truyền đi bất cứ đâu. – peastman

+0

Tôi đã thêm một ví dụ chi tiết. Hãy dùng thử. –

+0

Rất tiếc, lỗi của tôi. (Hay đúng hơn, lỗi của người ban đầu đã tạo ra mã SWIG.) Hóa ra có một số mã tiền xử lý tất cả các đối số, và đó là điều đã biến dict thành một tuple. – peastman

Các vấn đề liên quan