使用SWIG和C ++的std :: map时没有Java的迭代器

我已经在C ++中实现了一个带有std::map的类,并使用SWIG创建了从Java调用的接口。 但是没有迭代器对象允许我遍历SWIG包装的std::map的条目。 有谁知道如何创建迭代器?

为了能够在Java中迭代Object,它需要实现Iterable 。 这又需要一个名为iterator()的成员函数,它返回一个合适的Iterator实现。

从您的问题来看,不清楚您在地图中使用的是什么类型,以及您是否希望能够迭代对(如在C ++中),键或值。 三种变体的解决方案基本相似,下面我的例子选择了值。

首先,我用来测试这个SWIG接口文件的前导码:

 %module test %include "std_string.i" %include "std_map.i" 

为了实现可迭代的映射,我已经声明,定义并包装了SWIG接口文件中的另一个类。 这个类, MapIterator为我们实现了Iterator接口。 它是Java和包装C ++的混合体,其中一个比另一个更容易编写。 首先是一些Java,一个提供它实现的接口的类型映射,然后是Iterable接口所需的三个方法中的两个,以typemapforms给出:

 %typemap(javainterfaces) MapIterator "java.util.Iterator" %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(); } %} 

然后我们提供了MapIterator的C ++部分,它有一个私有实现,除了抛出next()部分exception和迭代器所需的状态(用std::map自己的const_iterator )。

 %javamethodmodifiers MapIterator::nextImpl "private"; %inline %{ struct MapIterator { typedef std::map 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& ret = *it++; return ret.second; } private: map_t::const_iterator it; const map_t& map; }; %} 

最后,我们需要告诉SWIG我们正在包装的std::map实现了Iterable接口,并提供了一个额外的成员函数,用于包装std::map ,它返回我们刚编写的MapIterator类的新实例:

 %typemap(javainterfaces) std::map "Iterable" %newobject std::map::iterator() const; %extend std::map { MapIterator *iterator() const { return new MapIterator(*$self); } } %template(MyMap) std::map; 

这可能是更通用的,例如用宏来隐藏地图的类型,这样如果你有多个地图,那么就像使用%template一样“调用”适当地图的宏。

原始类型的映射也有一点点复杂 – 你需要安排Java端使用Double / Integer而不是double / int (我相信是自动装箱这个术语),除非你决定在这种情况下包装对你可以与原始成员成对。