2016-04-07 12 views
4

BOOST_PYTHON_MODULEから使用)boost::python::class_を経由して、それを公開するboost::optional<T>型オブジェクトをラップする方法はありラップブースト::オプションのブーストを使用して::のpython

struct Foo 
{ 
    boost::optional<int> bar; 
}; 

BOOST_PYTHON_MODULE(module_name) 
{ 
    class_<Foo>("Foo") 
    .def_readwrite("bar", &Foo::bar); 
} 

は、この場合

ではAttributeErrorです
import module_name 
f = module_name.Foo() 
print f.bar 

の値がbarに設定されていません。 そしてTypeError

import module_name 
f = module_name.Foo() 
f.bar = "string" 

barint型です。

その他の関連する問題は、同様の方法で、コンテナタイプboost::python::indexing_suiteのクラスのオブジェクトをエクスポートすることです。

boost::python apiを使用すると問題は解決できますか?

+0

参照[この質問](http://stackoverflow.com/questions/26497922/how-to-wrap-ac -function-that-returns-boostoptionalt)が含まれます。おそらく、それが動作するための関数でなければならない場合は、setter/getterを使用してラップします。 –

答えて

4

exception translatorpython convertersが必要です。

例外トランスレータ

namespace bp = boost::python; 

// Custom exceptions 
struct AttributeError: std::exception 
{ 
    const char* what() const throw() { return "AttributeError exception"; } 
}; 

struct TypeError: std::exception 
{ 
    const char* what() const throw() { return "TypeError exception"; } 
}; 

// Set python exceptions 
void translate(const std::exception& e) 
{ 
    if(dynamic_cast<const AttributeError*>(&e)) 
    PyErr_SetString(PyExc_AttributeError, e.what()); 
    if(dynamic_cast<const TypeError*>(&e)) 
    PyErr_SetString(PyExc_TypeError, e.what()); 
} 

BOOST_PYTHON_MODULE(module_name) 
{ 
    // Exception translator 
    bp::register_exception_translator<AttributeError>(&translate); 
    bp::register_exception_translator<TypeError>(&translate); 
    ... 
} 

からパイソンコンバータ

template <typename T> 
struct to_python_optional 
{ 
    static PyObject* convert(const boost::optional<T>& obj) 
    { 
    if(obj) return bp::incref(bp::object(*obj).ptr()); 
    // raise AttributeError if any value hasn't been set yet 
    else throw AttributeError(); 
    } 
}; 

BOOST_PYTHON_MODULE(module_name) 
{ 
    ... 
    bp::to_python_converter<boost::optional<int>, 
          to_python_optional<int> >(); 
    ... 
} 

から、パイソンコンバータ

template<typename T> 
struct from_python_optional 
{ 
    static void* convertible(PyObject *obj_ptr) 
    { 
     try { return typename bp::extract<T>::extract(obj_ptr) ? obj_ptr : 0 ; } 
     // Without try catch it still raises a TypeError exception 
     // But this enables to custom your error message 
     catch(...) { throw TypeError(); } 
    } 

    static void construct(
    PyObject *obj_ptr, 
    boost::python::converter::rvalue_from_python_stage1_data* data) 
    { 
     const T value = typename bp::extract<T>::extract(obj_ptr); 

     assert(value); 

     void* storage = (
     (bp::converter::rvalue_from_python_storage<boost::optional<T> >*) 
     data)->storage.bytes; 

     new (storage) boost::optional<T>(value); 

     data->convertible = storage; 
    } 

    from_python_optional() 
    { 
    bp::converter::registry::push_back(
     &convertible, 
     &construct, 
     bp::type_id<boost::optional<T> >()); 
    } 
}; 

BOOST_PYTHON_MODULE(module_name) 
{ 
    ... 
    from_python_optional<int>(); 
    ... 
} 

さらに、def_readwrite(see this FAQ)のコンバーターを使用することはできません。add_propertyを使用する必要があります。

BOOST_PYTHON_MODULE(module_name) 
{ 
    ... 
    bp::class_<Foo>("Foo") 
    .add_property("bar", bp::make_getter(&Foo::bar, 
         bp::return_value_policy<bp::return_by_value>()), 
         bp::make_setter(&Foo::bar, 
         bp::return_value_policy<bp::return_by_value>())); 
} 

したがって、あなたのPythonインタプリタでこれらの出力を得ることができます:

>>> import module_name 
>>> f = module_name.Foo() 
>>> print f.bar 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: AttributeError exception 
>>> f.bar="string" 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: TypeError exception 
+0

ありがとう! 'struct'関数の' data'ポインタ引数は、メンバ変数Foo :: barが実際に格納されているメモリへのポインタですか?もしそうなら、 'new'の前にまだ使われていないというチェックがないのはなぜですか? もう1つの質問は 'return_value_policy'です: 1. voidを返すセッターの返品ポリシーを指定するのはなぜですか? 2.なぜ「return_by_value」ですか? –

+0

'data'ポインタは、変換の結果(python整数)のアドレスを保持します。 Boostのドキュメンテーションはこのテーマでは実際には貧弱ですので、ソースファイルを見なければなりません。 [rvalue_from_python_data.hpp](http://www.boost.org/doc/libs/1_61_0/boost/python/converter/rvalue_from_python_data.hpp)で、 'rvalue_from_python_storage'は' boost :: python :: detail :: referent_storage'と 'boost :: add_reference'を使ってメモリチャンクを取得します。 – cromod

+0

また、[add_reference.hpp](http://www.boost.org/doc/libs/1_61_0/boost/type_traits/add_reference.hpp)と[referent_storage.hpp](http:// www .boost.org/doc/libs/1_61_0/boost/python/detail/referent_storage.hpp)を参照してください。 – cromod

関連する問題