これは完全な答えではありません。質問が基づいていたmy previous answerからのギャップを記入できると仮定します。残念ながら、それはその場合より少し複雑です。
ただ、問題を定義する - のように、カスタムのC++クラスのパラメータを持っていると仮定します。
class cpp_class {
// some non-trivial contents
};
ので、あなたのC++インタフェースは次のようになります。
void call_some_std_func(std::function<void(cpp_class&)> callback) {
callback(5,std::string("hello"));
}
まず、C++クラス用のCythonラッパーを作成します(原則として、Boost Pythonラッパーを作成することができます)。ここでは、C++オブジェクトの「所有権」について選択する必要があります。私はメモリと外部コードから呼び出すことができ公にアクセスコンストラクタ関数を扱うデストラクタでラッパークラスを作成しました
cdef extern from "cpp_file.hpp":
cppclass cpp_class:
pass # details
cdef class CyWrapper:
cdef cpp_class* ptr
def __dealloc__(self):
del self.ptr
# other details following standard wrapper pattern
cdef public make_CyWrapper(cpp_class& x):
obj = CyWrapper()
obj.ptr = new cpp_class(x)
return obj
:最初の選択肢は、コピーを作成することです。このバージョンはラッパーが保持しているオブジェクトを所有しているため安全ではないため、無効なメモリへの書き込みはできません。ただし、コピーを作成するため、元のC++オブジェクトを変更することはできません。
2番目のオプションは、所有していないオブジェクトへのポインタを保持することです。しかし、あなたがオブジェクトを変更することができます - あなたはあなたのC++オブジェクトはCythonラッパーをoutlivesを確保する必要がある - これは安全ではありません
obj.ptr = &x // instead of new cpp_class(x)
:あなたは__dealloc__
を削除し、make_CyWrapper
にコピーを避ける以外のコードは基本的に同じです。
また、Cythonラッパーで既存のオブジェクトの所有権を得ることもできます(このようなスキームは、参照ではなくポインタを渡す必要があります。または、移動コンストラクタを使用できます)。あなたはC++クラスを基本型で表現された表現に分解し、それらをPythonに渡すことができます。共有ポインタを使用して所有権を分割することができます。保持しているC++インスタンスが破棄されると、Cythonラッパーを「無効」とマークするより精巧な方法があります。あなたが次の何
を使用すると、ブーストのPythonを使っているかどうか(それはPythonオブジェクトの便利な、呼び出し可能なラップだため)か、独自のバージョンを作っている場合に依存します。 (私は前の答えで両方の可能性を示した)。
と仮定すると、ブーストのPython、あなたは、2つのことを行う必要がある - 変換についてそれを言うと、それは(あなたが刺激的なセグメンテーションフォールトを取得しこれを行わない場合)あなたのラッパーを定義したモジュールをインポートしていることを確認してください
struct convert_to_PyWrapper {
static PyObject* convert(const cpp_class& rhs) {
// the const_cast here is a bit dodgy, but was needed to make it work
return make_CyWrapper(const_cast<cpp_class&>(rhs));
}
};
inline void setup_boost_python() {
PyInit_your_module_name(); // named inityour_module_name in Python 2
boost::python::to_python_converter<
cpp_class,
convert_to_PyWrapper>();
}
コールバックを使用しようとする前に、Python/Cythonコードが "setup_boost_python"を呼び出すようにする必要があります(インポート時にモジュールレベルに置いた方が理想的です)。
「手動」スキーム(Boost Pythonへの依存を避ける)に従っている場合は、C++ to Cython型変換を行うcall_obj
Cython関数を変更する必要があります。
cdef public void call_obj(obj, cpp_class& c):
obj(make_CyWrapper(c))
また、使用する前にラッパーのCythonモジュールをインポートする必要があります(そうしないと、セグメンテーションフォルトが発生します)。私は "py_object_wrapper.hpp"でこれを行いましたが、あなたが好きなところに置くことができれば、それを一度どこかで行うことができます。
void operator()(cpp_class& a) {
PyInit_your_module_name();
if (held) {
call_obj(held,a);
}
}
あなたは何をしようとしているかを示す完全ではあるが最小限の例を挙げることができますか? – metal