分两行:创建一个接口函数,它将命令作为字符串并设置一个仿函数,然后将其分配给std::function
. operator()
负责评估目标语言中的字符串。
让我们假设在头文件mymodule.hh
中有一个类,其中MyModule
的方法是另一个对象。void MyModule::Func(const std::function<double(Bunch&)> & func)
Bunch
这可以通过定义一个接口函数来解决,该函数接受一个const char *
表示表达式的 eval 并将其包装到一个仿函数中,然后将其分配给std::function
. 好消息是,这完全可以在 swig 接口文件中完成,无需接触 C++ 代码,方法如下(我使用了 tcl,你只需要适应operator()
):
%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 访问当前Bunch
在 C++ 中处理的方法。该函数:SWIG_NewInstanceObj
允许将Bunch
指针转换为目标语言的表示形式并在解释器中创建它的一个实例(此函数没有记录,但在任何 swig 生成的包装文件中挖掘一点并不难理解它机制)。使用以下命令,我将该对象设置为一个名为的变量bunch
,以便用户只需使用它就可以使用它,$bunch
然后可以访问使用 swig 导出的所有方法。
多亏了 swig,我认为用这么少的代码就可以实现如此强大的功能真是太神奇了!