gpt4 book ai didi

c++ - 为使用 class_<> 导出的类绕过 to_python 注册表?

转载 作者:太空狗 更新时间:2023-10-29 21:23:37 25 4
gpt4 key购买 nike

这是一个我无法使用文档回答的 boost.python 问题。

我有两个 C++ 类 A 和 B,这样 B 是 A 的子类,在某些条件下,类型 A 的对象可以转换为类型 B 的对象。这两个类都使用 class_< >。示意性地:

class A 
{
public:
bool is_B() const { ... } // returns true if conversion to B will succeed
...
};

class B : public A {
B(const A &a) { ... } // should only be called if a.is_B() == true
...
};

class_<A>("A") ... ;
class_<B,bases<A> >("B") ... ;

如果可能的话,我希望 A 类的到 Python 转换器返回 B 类的对象;否则它应该返回一个类 A 的对象。示意性地:

 struct A_to_python_converter {
PyObject *convert(const A &a) {
if (a.is_B())
// return object of class B
return boost::python::incref(boost::python::object(B(a)).ptr());
else
... // return object of class A
}
}

boost::python::to_python_converter<A,A_to_python_converter>();

问题是我不确定用什么代码代替上面的“...”。如果我把:

// return object of class A
return boost::python::incref(boost::python::object(a).ptr());

然后我得到一个无限循环,因为 A_to_python_converter::convert() 将被递归调用。有没有一种方法可以绕过注册表,并将 A 类的对象转换为 (PyObject *) 而无需通过 A_to_python_converter,因为 A 已经使用 class_<> 导出?这将彻底解决我的问题(尽管我愿意接受其他建议)。

谢谢!K

最佳答案

一个类型只需要注册一个到 Python 的转换。

当类通过 boost::python::class_ 公开时, 类型信息和注册发生。此外,如果未提供 boost::noncopyable,则会注册将按值复制 T 的到 Python 和从 Python 的转换器。用户可以使用 boost::python::to_python_converter 注册自己的自定义转换器.

因此,一种解决方案是使用 boost::noncopyable 抑制类 A 的默认转换器,然后注册一个自定义转换器,该转换器将创建包含任一实例的 Python 对象AB 的实例。这种方法将在 Boost.Python 中使用较低级别的 API 来处理实例创建。

/// @brief Custom converter that converts A to either an A or B Python object.
struct class_A_cref_wrapper
: boost::python::to_python_converter<A, class_A_cref_wrapper>
{
// Type that makes instances that hold A by value.
typedef boost::python::objects::make_instance<A,
boost::python::objects::value_holder<A>
> instance_maker;

static PyObject* convert(const A& a)
{
namespace python = boost::python;
return a.is_B()
? python::incref(python::object(B(a)).ptr()) // Create B.
: instance_maker::execute(boost::ref(a)); // Create A.
}
};

这是一个完整的例子demonstrating这种方法:

#include <boost/python.hpp>

// Legacy API.
class A
{
public:
A() : b_(false) {}
A(bool b) : b_(b) {}
bool is_B() const { return b_; } // true if conversion to B will succeed
private:
bool b_;
};

class B: public A
{
public:
B() : A() {}
B(const A& a) : A(a) {}
};

/// @brief Factory functions that return an A type with is_B of false.
A make_A() { return A(false); }

/// @brief Factory functions that return an A type with is_B of true.
A make_B() { return A(true); }

/// @brief Custom converter that converts A to either an A or B Python object.
struct class_A_cref_wrapper
: boost::python::to_python_converter<A, class_A_cref_wrapper>
{
// Make and hold instances by value.
typedef boost::python::objects::make_instance<A,
boost::python::objects::value_holder<A>
> instance_maker;

static PyObject* convert(const A& a)
{
namespace python = boost::python;
return a.is_B()
? python::incref(python::object(B(a)).ptr()) // Create B.
: instance_maker::execute(boost::ref(a)); // Create A.
}
};

BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;

// Expose A and B classes. Use boost::noncopyable to suppress to-Python
// and from-Python converter regristration for class A.
python::class_<A, boost::noncopyable>("A");
python::class_<B, python::bases<A> >("B");

// Register a custom converter for A.
class_A_cref_wrapper();

// Expose factory functions that always return an A type. This will
// cause to_python converters to be invoked when invoked from Python.
python::def("make_A", &make_A);
python::def("make_B", &make_B);
}

交互使用:

>>> import example
>>> assert(isinstance(example.make_A(), example.A))
>>> assert(isinstance(example.make_B(), example.B))
>>> assert(isinstance(example.make_B(), example.A))
>>> assert(not isinstance(example.make_A(), example.B))

关于c++ - 为使用 class_<> 导出的类绕过 to_python 注册表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17824901/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com