2012-02-27 24 views
6

Tôi đã triển khai một lớp với std::map trong C++ và tạo giao diện bằng SWIG để gọi từ Java. Tuy nhiên không có đối tượng trình lặp nào cho phép tôi lặp qua các mục trong SWIG được bọc std::map. Có ai biết làm thế nào để tạo ra một iterator?Không có trình lặp cho Java khi sử dụng SWIG với C++ 's std :: map

+0

Bạn sẽ cần phải chính xác những gì bạn có nghĩa là không phải là "tất cả" mục. Bất cứ điều gì cụ thể, như mục cuối cùng bị thiếu? Chia sẻ một số mã để chỉ cho chúng tôi cách bạn đã thực hiện tương tác? –

+0

Xin lỗi, chính xác là tôi không thể thực hiện bất kỳ sự lặp lại nào. – delita

+1

Tìm kiếm nhanh trên Google đã tìm thấy điều này: http://chadretz.wordpress.com/2009/11/27/stl-collections-with-java-and-swig/ Có thể nó sẽ giúp – Tim

Trả lời

10

Để có thể lặp qua đối tượng trong Java, nó cần triển khai Iterable. Điều này đến lượt nó đòi hỏi một hàm thành viên được gọi là iterator() trả về việc thực hiện phù hợp một số Iterator.

Từ câu hỏi của bạn, không rõ loại bạn đang sử dụng trên bản đồ và nếu bạn muốn có thể lặp qua các cặp (như trong C++), các phím hoặc giá trị. Các giải pháp cho ba biến thể là tương tự đáng kể, ví dụ của tôi dưới đây đã chọn các giá trị.

Trước tiên, lời mở đầu cho các tập tin giao diện SWIG tôi sử dụng để kiểm tra điều này:

%module test 

%include "std_string.i" 
%include "std_map.i" 

Để thực hiện bản đồ iterable Tôi đã tuyên bố, xác định và được bao bọc một lớp khác trong file giao diện SWIG . Lớp này, MapIterator triển khai giao diện Iterator cho chúng tôi. Đó là một hỗn hợp của cả Java và gói C++, nơi mà một trong những đã được dễ dàng hơn khác để viết. Thứ nhất một số Java, một typemap cung cấp cho giao diện nó thực hiện và sau đó hai trong ba phương pháp cần thiết cho việc giao diện Iterable, được coi là một typemap:

%typemap(javainterfaces) MapIterator "java.util.Iterator<String>" 
%typemap(javacode) MapIterator %{ 
    public void remove() throws UnsupportedOperationException { 
    throw new UnsupportedOperationException(); 
    } 

    public String next() throws java.util.NoSuchElementException { 
    if (!hasNext()) { 
     throw new java.util.NoSuchElementException(); 
    } 

    return nextImpl(); 
    } 
%} 

Sau đó, chúng tôi cung cấp C++ phần của MapIterator, trong đó có một tin thực hiện tất cả ngoại trừ việc ném một phần của next() và trạng thái cần thiết cho trình lặp (được biểu thị theo số const_iterator riêng của std::map).

%javamethodmodifiers MapIterator::nextImpl "private"; 
%inline %{ 
    struct MapIterator { 
    typedef std::map<int,std::string> map_t; 
    MapIterator(const map_t& m) : it(m.begin()), map(m) {} 
    bool hasNext() const { 
     return it != map.end(); 
    } 

    const std::string& nextImpl() { 
     const std::pair<int,std::string>& ret = *it++; 
     return ret.second; 
    } 
    private: 
    map_t::const_iterator it; 
    const map_t& map;  
    }; 
%} 

Cuối cùng chúng ta cần phải nói SWIG rằng std::map chúng tôi đang quấn cụ giao diện Iterable và cung cấp một chức năng thành viên bổ sung cho các mục đích của gói std::map mà trả về một thể hiện mới của lớp MapIterator chúng tôi chỉ viết:

%typemap(javainterfaces) std::map<int,std::string> "Iterable<String>" 

%newobject std::map<int,std::string>::iterator() const; 
%extend std::map<int,std::string> { 
    MapIterator *iterator() const { 
    return new MapIterator(*$self); 
    } 
} 

%template(MyMap) std::map<int,std::string>; 

Điều này có thể chung chung hơn, với các macro ví dụ để che giấu các loại bản đồ như vậy nếu bạn có nhiều bản đồ nó chỉ là một vấn đề "gọi" vĩ mô cho các bản đồ thích hợp giống như bạn làm với %template .

Ngoài ra còn có một biến chứng nhẹ với bản đồ của các loại nguyên thủy - bạn sẽ cần phải sắp xếp cho phía Java để sử dụng Double/Integer thay vì double/int (autoboxing Tôi tin là thuật ngữ), trừ khi bạn quyết định quấn cặp trong trường hợp đó bạn có thể tạo ra một cặp với các thành viên nguyên thủy.

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