使用boost::python包装boost::可选

使用boost::python包装boost::可选,python,c++,boost,boost-python,boost-optional,Python,C++,Boost,Boost Python,Boost Optional,是否有一种方法可以包装boost::optional类型对象,通过boost::python::class(从boost\u python\u模块使用)将其公开 因为还没有设置条的值。 和TypeError import module_name f = module_name.Foo() f.bar = "string" bar属于int类型 另一个相关问题是以同样的方式导出boost::python::index_suite容器类型的类对象 使用boost::pythonapi可以解决这个问

是否有一种方法可以包装
boost::optional
类型对象,通过
boost::python::class
(从
boost\u python\u模块使用)将其公开

因为还没有设置
条的值。
和
TypeError

import module_name
f = module_name.Foo()
f.bar = "string"
bar
属于
int
类型

另一个相关问题是以同样的方式导出
boost::python::index_suite
容器类型的类对象

使用
boost::python
api可以解决这个问题吗?

您需要一个and

异常转换器

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>();
  ...
}
因此,您将在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
>>导入模块\u名称
>>>f=模块名称。Foo()
>>>打印f.bar
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
AttributeError:AttributeError异常
>>>f.bar=“字符串”
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TypeError:TypeError异常

请参阅。如果它需要一个函数才能工作,那么可以使用setter/getter来包装它。谢谢!
construct
function中的
data
指针参数是指向存储成员变量Foo::bar的内存的指针吗??如果是这样,那么为什么在
新建之前没有检查它是否未被使用?另一个问题是关于
返回值\u策略
:1。为什么我们要为返回无效的setter指定任何返回策略?2.为什么它是
按\u值返回\u
数据
指针保存转换结果的地址(python整数)。Boost文档在这个主题上非常糟糕,所以我们必须查看源文件。在中,我们可以看到
rvalue\u from\u python\u storage
使用
boost::python::detail::referent\u storage
boost::add\u reference
来获取内存块。您还可以查看和。事实上,
return\u value\u policy
不需要指定setter(我刚刚检查过它)。我盲目地遵循Boost的常见问题:PIn你会发现不同的退货政策。我选择
return\by\u value
,因为我知道您想要得到一个值。
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>();
  ...
}
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>()));
}
>>> 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