2017-08-29 3 views
1

が答える前に、この記事をお読みください:Pythonの関数はブーストのPythonを使用してstd::functionに変換され、どのように受け入れられて答えてPass a closure from Cython to C++Cython:カスタムパラメータの種類とはstd ::関数コールバック

は、それがきちんと示されています。

この例では、std::functionを引数としてラップし、入力としてPython関数を使用して呼び出すことができます。しかし、同様のカスタムタイプのためにこの作業を行う方法についてstd::functionパラメータがintのようなプリミティブ、doublestringなどしているとき、これが唯一

に動作します任意の指導は非常に理解されるであろう。

+1

あなたは何をしようとしているかを示す完全ではあるが最小限の例を挙げることができますか? – metal

答えて

1

これは完全な答えではありません。質問が基づいていた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); 
    } 
} 
+0

(これはBoost Pythonのものではなく、私の具体的な実装で動作します。私ができる時にBoost Pythonで動作させる方法を見ていきます) – DavidW

+0

Davidの詳細な回答ありがとうございます。それを行うPythonの方法。私はこの方法で何かが必要だと思う:http://www.boost.org/doc/libs/1_62_0/libs/python/doc/html/faq/how_can_i_automatically_convert_.html –

+0

私はブースト・パイソンの方法が正しいと思った私はあなたのリンクが正しいアイデアだと思う:Cythonでコンバータを作ったと思う(おそらく上記のようなラッパークラスを使う)、 'cdef public'コンバータ関数を作るC++クラスを取り込み、ラッパーを返し、 'boost :: python :: to_python_converter'を使用します。私はそれを見る時間がある前に、おそらく1日かそれ以上になるでしょう。あなたや他の誰かがそれを素早く把握すれば、投稿してください... – DavidW

関連する問題