当前位置: 首页 > 知识库问答 >
问题:

用SWIG处理std::函数

穆承运
2023-03-14

显然,SWIG不理解std::function并破坏Python绑定。例如,这适用于C:

// Somewhere in the API
typedef std::function<void(const UnitError & error)> UnitErrorHandler;

// Somewhere else in the API
void Unit::setErrorHandler(const UnitErrorHandler & handler) {}

// In the application code
unit->setErrorHandler([](const UnitError & error){
    std::cerr << error << std::endl;
    std::exit(1);
});

但是这会破坏代码(除了为了简单起见有不同的行为,但这不是重点):

unit.setErrorHandler(lambda error: len(error))

def(普通)未绑定函数的情况相同。那么,有人知道解决这个问题的方法吗?

共有2个答案

沙柏
2023-03-14

两行:创建一个接口函数,该函数将命令作为字符串,并设置一个仿函数,然后将其分配给std::function运算符()负责计算目标语言中的字符串。

让我们假设在头文件mymodule中。hh您有一个类MyModule,它有一个方法void MyModule::Func(const std::function

这可以通过定义一个接口函数来解决,该函数接受一个表示要求值的表达式的const char*,并将其包装成一个函子,然后将其分配给std::function。好消息是,这完全可以在swig接口文件中完成,而无需接触C代码,下面是如何(我使用了tcl,您只需调整操作符()):

%module mymodule
%{
  #include "bunch.hh"
  #include "mymodule.hh"

  extern Tcl_Interp* tcl_interp;

  struct Tcl_bunch_callback {
    std::string callback;
    double operator()(Bunch & bunch)
    {
      Tcl_Obj * bunch_obj = SWIG_Tcl_NewInstanceObj(tcl_interp, &bunch, SWIGTYPE_p_Bunch, /*own pointer?*/0);
      Tcl_SetVar2Ex(tcl_interp, "bunch", (const char*)nullptr, bunch_obj, 0);
      double resultValue;
      const int resultCode = Tcl_ExprDouble(tcl_interp, callback.c_str(), &resultValue);
      if (resultCode != TCL_OK) {
        std::cerr << "WARNING evaluation of tcl expression failed: " 
                  << Tcl_GetStringResult(tcl_interp) << std::endl;
        resultValue = max_double;
      }
      Tcl_DeleteCommand(tcl_interp, Tcl_GetString(bunch_obj)); //remove the used command to avoid leaks
      return resultValue;
    }
  };
%}

%include "bunch.hh"
%include "mymodule.hh"
%extend MyModule
{
  void Func(const char * cmd) {
    $self->Func(std::function<double(Bunch&)>(Tcl_bunch_callback(cmd)));
  }
}

在我的例子中,operator()非常适合Tcl,但我相信其他目标语言也可以编写类似的过程。下面是一些细节。

我为用户提供了直接从Tcl访问当前用C处理的Bunch方法的能力。函数:SWIG_NewInstanceObj允许转换目标语言中表示的Bunch指针,并在解释器中创建它的一个实例(此函数没有文档记录,但在SWIG生成的任何wrap文件中挖掘一点并不难理解其机制)。使用下面的命令,我将该对象设置为一个名为bunch的变量,这样用户只需使用$bunch即可使用该对象,然后就可以访问使用swig导出的所有方法。

我认为令人惊讶的是,由于痛饮,如此强大的东西是如何用如此少的代码行提供的!

葛驰
2023-03-14

std::function相对较新(C11),因此SWIG没有任何现成的解决方案。虽然不那么灵活,但您可以使用函数指针,但需要注意。在文档中引用5.4.9指向函数和回调的指针:

...SWIG提供了对函数指针的完全支持,前提是回调函数是用C语言定义的,而不是用目标语言定义的。

所以传递一个lambda是不起作用的。阅读文档链接了解一些替代方案。

 类似资料:
  • 在使用google或tools的路由解算器时,会引发运行时错误。在收到此错误之前和之后,代码段中没有任何更改。以前,它是有效的。但最近在修改了数据库连接后,我发现了这个错误。(不过,我怀疑dB连接修改会如何影响路由解算器) 我正在使用Azure Databricks笔记本。由于我对运筹学还不熟悉,所以我以https://developers.google.com/optimization/rout

  • 问题内容: 我正在使用SWIG从Java访问C ++代码。 公开非常量引用传递的std :: string参数的最简单方法是什么? 我有参考暴露为Java数组传递原语,感谢typemaps.i,和s ^暴露,感谢std_string.i。但是非const std :: string&被公开为不透明指针类型。 当前: 期望的: 更新 :我找到 了 解决方案,如下所述。但是,它花费了超过几秒钟的时间。

  • 问题内容: 我已经看到了很多类似的问题,但是还没有找到解决我特定问题的方法。我正在尝试SWIGify一些使用std :: function的C ++ 11代码,因此可以在Java应用程序中使用它。 我遇到了这样的共享指针: 并使用shared_ptr指令成功处理了它们,如下所示: 我遇到了像这样的共享指针向量: 并使用如下模板成功处理了它们: 现在我有一个这样的方法: 而且我无法让SWIG正确包装

  • 问题内容: 我试图弄清楚需要更改什么SWIG接口文件才能处理getFoo返回一个指向自定义结构数组(sender_id_t)的指针。没有任何特殊的SWIG接口代码,我只得到Java端的指针。如何将指针转换为可以循环或迭代的内容(在Java中),以便获取每个sender_id_t id值?感谢任何建议。 C结构: C函数: 例外: 问题答案: 最简单的解决方案不涉及编写任何JNI,实际上是方法2。因

  • 我已经创建了swig接口文件来为我的C文件创建JNI。但是我的一些C文件包含一些函数,这些函数接受指针作为参数,比如(void*),C BOOL和Swig将其转换为SWIGTYPE_p_int32_t如何从java传递这种数据类型? 例如,函数的一个实际原型在C中如下所示 它通过swig转换成Java文件 如何从java传递这样的值? 我有许多类在函数中包含此类参数。有什么方法可以让我尽可能简单地

  • 问题内容: 我正在尝试使用SWIG将C 类包装到Java类中。此类C 类具有引发异常的方法。 我有三个目标,尽管据我所知遵循了手册,但目前没有一个目标: 要使Java类在C ++中引发的方法上声明 要获取SWIG生成的Exception类以进行扩展 在生成的SWIG类中重写。 似乎问题的根源似乎没有应用我的,因为以上均未发生。我做错了什么? 最小的示例如下。C ++不必编译,我只对生成的Java感