2012-02-27 8 views
6

Zaimplementowałem klasę z std::map w C++ i stworzyłem interfejs, używając SWIG do wywołania z Javy. Jednak nie ma obiektu iteratora, który pozwala mi na iterację poprzez wpisy w SWIG opakowane std::map. Czy ktoś wie, jak utworzyć iterator?Bez iteratora dla Javy przy użyciu SWIG z C++ std :: map

+0

Musisz sprecyzować, co masz na myśli, nie "wszystkie" wpisy. Coś konkretnego, jak brakujący ostatni element? Udostępnienie jakiegoś kodu, aby pokazać nam, jak wykonałeś interop? –

+0

Przykro mi, ale nie jestem w stanie wykonać żadnej iteracji. – delita

+1

Szybkie wyszukiwanie Google wykryło: http://chadretz.wordpress.com/2009/11/27/stl-collections-with-java-and-swig/ Może to pomaga – Tim

Odpowiedz

10

Aby móc dokonywać iteracji obiektów w języku Java, konieczne jest wdrożenie Iterable. To z kolei wymaga funkcji składowej o nazwie iterator(), która zwraca odpowiednią implementację Iterator.

Z twojego pytania nie jest całkiem jasne, jakie typy używasz na mapie i czy chcesz mieć możliwość iteracji po parach (jak w C++), kluczy lub wartości. Roztwory trzech wariantów są zasadniczo podobne, mój przykład poniżej wybrał wartości.

początek preambuła do pliku interfejsu SWIG I używany do testowania to:

%module test 

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

W celu realizacji mapę iterable Mam zadeklarowanej, zdefiniowane i owinięte innej klasy w pliku interfejsów SWIG . Ta klasa, MapIterator, implementuje dla nas interfejs Iterator. Jest to mieszanka zarówno języka Java, jak i opakowanego C++, w którym jeden był łatwiejszy do napisania. Po pierwsze niektóre Java, A typemap który daje interfejs to implementuje a następnie dwa z trzech metod wymaganych dla interfejsu Iterable, przekazana jako 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(); 
    } 
%} 

Następnie dostarczamy C++ część MapIterator, który ma prywatny implementacja wszystkich wyjątków polegających na wyrzuceniu części z next() i stanu niezbędnego dla iteratora (wyrażonego w postaci std::map z własnego const_iterator).

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

Wreszcie musimy powiedzieć SWIG że std::map jesteśmy owijania implementuje interfejs Iterable i zapewniają dodatkową funkcję składową dla celów owijania std::map która zwraca nową instancję klasy MapIterator po prostu napisał:

%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>; 

to może być bardziej ogólne, z makrami na przykład ukryć typy mapie tak, że jeśli masz wiele map to tylko kwestia „powołanie” makro na odpowiednich mapach jak zrobić z %template .

Istnieje również niewielka komplikacja z mapami prymitywnych typów - trzeba zorganizować stronie Java używać Double/Integer zamiast double/int (autoboxing wierzę, to termin), chyba że zdecydował się zawinąć par już w takim przypadku możesz stworzyć parę z prymitywnymi członkami.