2 行で: コマンドを文字列として受け取り、 に割り当てられるファンクターを設定するインターフェイス関数を作成しますstd::function
。はoperator()
、ターゲット言語で文字列を評価します。
ヘッダー ファイルに、別のオブジェクトであるメソッドをmymodule.hh
持つクラスがあると仮定しましょう。MyModule
void MyModule::Func(const std::function<double(Bunch&)> & func)
Bunch
const char *
これは、式を表す を eval に取り、それを に割り当てられるファンクターにラップするインターフェイス関数を定義することで解決できますstd::function
。良いニュースは、これは C++ コードに触れることなく、swig インターフェイス ファイルで完全に実行できることです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 に限定されていますが、他のターゲット言語についても同様の手順を記述できると確信しています。それのいくつかの詳細に従います。
ユーザーが現在Bunch
C++ で処理されているメソッドに Tcl から直接アクセスできるようにします。関数:ポインターをターゲット言語での表現SWIG_NewInstanceObj
に変換Bunch
し、インタープリターでそのインスタンスを作成できます (この関数は文書化されていませんが、swig で生成されたラップ ファイルを少し掘り下げると、理解するのは難しくありません。機構)。次のコマンドを使用して、そのオブジェクトを名前付きの変数に設定しbunch
て、ユーザーが簡単に使用できるようにし、$bunch
swig でエクスポートされたすべてのメソッドにアクセスできるようにします。
swig のおかげで、これほど強力なものがわずかなコード行で利用できるようになったのは驚くべきことだと思います。