将 SWIG 与 C++ 的 std::map 一起使用时,Java 没有迭代器

Posted

技术标签:

【中文标题】将 SWIG 与 C++ 的 std::map 一起使用时,Java 没有迭代器【英文标题】:No iterator for Java when using SWIG with C++'s std::map 【发布时间】:2012-02-27 13:31:44 【问题描述】:

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

【问题讨论】:

您需要准确说明不是“所有”条目的含义。有什么具体的,比如最后一项丢失了吗?分享一些代码,向我们展示您是如何进行互操作的? 抱歉,确切地说,我根本无法执行任何迭代。 快速谷歌搜索发现:chadretz.wordpress.com/2009/11/27/…也许有帮助 【参考方案1】:

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

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

首先,我用来测试的 SWIG 接口文件的序言:

%module test

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

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

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

然后我们提供MapIterator 的C++ 部分,除了next() 的异常抛出部分和迭代器所需的状态(以std::map 自己的@987654332 表示@)。

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

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

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

这可能更通用,例如使用宏来隐藏地图的类型,这样如果您有多个地图,只需像使用%template 一样为适当的地图“调用”宏。

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

【讨论】:

以上是关于将 SWIG 与 C++ 的 std::map 一起使用时,Java 没有迭代器的主要内容,如果未能解决你的问题,请参考以下文章

SWIG:使用带有 shared_ptr 的 std::map 访问器?

C++ 将预先保留的哈希映射(std::unordered_map)与整数键和连续数据数组(std::vector)进行比较

将 SWIG 与 C++ 模板函数一起使用

如何使用 SWIG 将 C++ 数组转换为 Python 列表?

C++ std::map 和 std::vector 的优点? [关闭]

Cython C++ 和 std::map 处理