5

明らかに、SWIG はstd::functionPython バインディングを理解せず、壊します。たとえば、これは 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(通常の) バインドされていない関数と同じです。それで、誰もこれに対する回避策を知っていますか?

4

2 に答える 2

1

2 行で: コマンドを文字列として受け取り、 に割り当てられるファンクターを設定するインターフェイス関数を作成しますstd::function。はoperator()、ターゲット言語で文字列を評価します。


ヘッダー ファイルに、別のオブジェクトであるメソッドをmymodule.hh持つクラスがあると仮定しましょう。MyModulevoid 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 に限定されていますが、他のターゲット言語についても同様の手順を記述できると確信しています。それのいくつかの詳細に従います。

ユーザーが現在BunchC++ で処理されているメソッドに Tcl から直接アクセスできるようにします。関数:ポインターをターゲット言語での表現SWIG_NewInstanceObjに変換Bunchし、インタープリターでそのインスタンスを作成できます (この関数は文書化されていませんが、swig で生成されたラップ ファイルを少し掘り下げると、理解するのは難しくありません。機構)。次のコマンドを使用して、そのオブジェクトを名前付きの変数に設定しbunchて、ユーザーが簡単に使用できるようにし、$bunchswig でエクスポートされたすべてのメソッドにアクセスできるようにします。

swig のおかげで、これほど強力なものがわずかなコード行で利用できるようになったのは驚くべきことだと思います。

于 2014-08-07T07:45:53.000 に答える
1

std::functionは比較的新しい (C++11) ため、SWIG にはすぐに使えるソリューションはありません。柔軟ではありませんが、関数ポインターを使用できますが、注意が必要です。ドキュメント内の関数およびコールバックへの 5.4.9 ポインタの引用:

...SWIG は、コールバック関数がターゲット言語ではなく C で定義されている場合、関数ポインターを完全にサポートします。

したがって、ラムダを渡しても機能しません。いくつかの代替手段については、ドキュメント リンクを参照してください。

于 2013-06-26T03:38:28.200 に答える