gpt4 book ai didi

c++ - 在 Boost.Python : wrong type 中的类中存储和检索指针时出现 ArgumentError

转载 作者:太空宇宙 更新时间:2023-11-04 11:47:14 24 4
gpt4 key购买 nike

我在带有 MSVC2010 的 Windows 上使用 Boost.Python 1.54,我在从 python 将指向一个类的指针存储到第二个类中并检索它时遇到问题。它似乎以某种方式改变了数据类型。

这是我的类(class):

typedef unsigned int uint_t;

struct classA {
int intval;
unsigned int bitfield_member:1;
};

struct Collection {
classA * class_a_ptr;
};

下面是我如何将它们暴露给 python(其中一些代码最初是由 Py++ 自动生成的,但从那时起我就手动编辑了它):

#include <boost/python.hpp>
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#include <boost/python/return_value_policy.hpp>
#include <boost/python/manage_new_object.hpp>

namespace bp = boost::python;

struct Collection_wrapper : Collection, bp::wrapper< Collection > {

Collection_wrapper(Collection const & arg )
: Collection( arg )
, bp::wrapper< Collection >(){
// copy constructor

}

Collection_wrapper()
: Collection()
, bp::wrapper< Collection >(){
// null constructor

}

static ::classA * get_class_a_ptr(Collection const & inst ){
return inst.class_a_ptr;
}

static void set_class_a_ptr( Collection & inst, ::classA * new_value ){
inst.class_a_ptr = new_value;
}
};

struct classA_wrapper : classA, bp::wrapper< classA > {

classA_wrapper(classA const & arg )
: classA( arg )
, bp::wrapper< classA >(){
// copy constructor

}

classA_wrapper()
: classA()
, bp::wrapper< classA >(){
// null constructor

}

::uint_t get_bitfield_member() const {
return bitfield_member;
}

void set_bitfield_member( ::uint_t new_value ){
bitfield_member = new_value;
}
};

BOOST_PYTHON_MODULE(render_lib_ext)

{
using namespace bp;

{ //::Collection
typedef bp::class_< Collection_wrapper > Collection_exposer_t;
Collection_exposer_t Collection_exposer = Collection_exposer_t( "Collection" );
bp::scope Collection_scope( Collection_exposer );
// original version, fails
Collection_exposer.add_property( "class_a_ptr"
, bp::make_function( (::classA * (*)( ::Collection const & ))(&Collection_wrapper::get_class_a_ptr), bp::return_internal_reference< >() )
, bp::make_function( (void (*)( ::Collection &,::classA * ))(&Collection_wrapper::set_class_a_ptr), bp::with_custodian_and_ward_postcall< 1, 2 >() ) );
}

{ //::classA
typedef bp::class_< classA_wrapper > classA_exposer_t;
classA_exposer_t classA_exposer = classA_exposer_t( "classA" );
bp::scope classA_scope( classA_exposer );
classA_exposer.def_readwrite( "intval", &classA::intval );
classA_exposer.add_property( "bitfield_member"
, (::uint_t ( classA_wrapper::* )( ) const)(&classA_wrapper::get_bitfield_member)
, (void ( classA_wrapper::* )( ::uint_t ) )(&classA_wrapper::set_bitfield_member) );
}
}

下面是运行它的 python 测试:

import unittest
import render_lib_ext as RL

class TestRenderLib(unittest.TestCase):

def test_globals(self):
coll=RL.Collection()
g = RL.classA()
g.intval=9801;
self.assertEqual(9801, g.intval)
coll.class_a_ptr = g # store pointer in collection
geg = coll.class_a_ptr # retrieve it
self.assertEqual(0, g.bitfield_member) # works
self.assertEqual(0, geg.bitfield_member) # fails with ArgumentError (type error)
self.assertEqual(9801, geg.intval) # fails! Is it not the same object?

它在第一个“失败”行出现此错误而失败:

Traceback (most recent call last):
File "test2.py", line 18, in test_globals
self.assertEqual(0, geg.bitfield_member) # fails with ArgumentError (type error)
ArgumentError: Python argument types in
None.None(classA)
did not match C++ signature:
None(struct classA_wrapper {lvalue})

这对我来说似乎很奇怪,因为 classA_wrapper 扩展了 classA。我究竟做错了什么?有没有不同的方法来做到这一点?我在 python 和 c++ 方面非常有经验,但这是我第一次涉足 Boost.Python。

最佳答案

暴露给 classA 上的 bitfield_member 属性的仿函数需要显式接受它们操作的实例。它相当于 property() Python 中的方法,其中 fgetfset 接受 self 参数。因此,将 bitfield_member getter 和 setter 函数更改为静态的,并接受 classA& 作为它们的第一个参数。

// ...

struct classA_wrapper: ...
{
// ...

static ::uint_t get_bitfield_member(classA& self)
{
return self.bitfield_member;
}

static void set_bitfield_member(classA& self, ::uint_t new_value)
{
self.bitfield_member = new_value;
}
};

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

// ...

python::class_< classA_wrapper >("classA")
.def_readwrite("intval", &classA::intval)
.add_property("bitfield_member",
&classA_wrapper::get_bitfield_member,
&classA_wrapper::set_bitfield_member)
;
}
}

虽然get_bitfield_memberset_bitfield_member在原代码中是成员函数,但是class_a_ptr返回的PythonclassA对象似乎没有完全初始化其底层 C++ 类型。这可能是 Boost.Python API 中未定义行为的结果。

问题没有出现在其他地方,因为:

  • Collection.class_a_ptr 属性的 fgetfset 显式接受实例参数。
  • classA.intval 属性使用 def_readwrite,它将隐式创建 fgetfset 接受实例make_getter/make_setter .

这是一个基于原始代码的完整示例:

#include <boost/python.hpp>

typedef unsigned int uint_t;

struct classA
{
int intval;
unsigned int bitfield_member:1;
};

struct Collection
{
classA * class_a_ptr;
};

namespace python = boost::python;

struct Collection_wrapper
: Collection, python::wrapper<Collection>
{
Collection_wrapper() {}

Collection_wrapper(const Collection& self)
: Collection(self)
{}

static ::classA* get_class_a_ptr(const Collection& self)
{
return self.class_a_ptr;
}

static void set_class_a_ptr(Collection& self, ::classA * new_value)
{
self.class_a_ptr = new_value;
}
};

struct classA_wrapper
: classA, python::wrapper<classA>
{
classA_wrapper() {}

classA_wrapper(const classA& self)
: classA(self)
{}

static ::uint_t get_bitfield_member(const classA& self)
{
return self.bitfield_member;
}

static void set_bitfield_member(classA& self, ::uint_t new_value)
{
self.bitfield_member = new_value;
}
};

BOOST_PYTHON_MODULE(example)
{
python::class_<Collection_wrapper>("Collection")
.add_property("class_a_ptr",
python::make_function(&Collection_wrapper::get_class_a_ptr,
python::return_internal_reference<>()),
python::make_function(&Collection_wrapper::set_class_a_ptr,
python::with_custodian_and_ward_postcall<1, 2>()))
;

python::class_<classA_wrapper>("classA")
.def_readwrite("intval", &classA::intval)
.add_property("bitfield_member",
&classA_wrapper::get_bitfield_member,
&classA_wrapper::set_bitfield_member)
;
}

及其用法:

>>> import example
>>> collection = example.Collection()
>>> a = example.classA()
>>> a.intval = 9801
>>> print a.intval
9801
>>> collection.class_a_ptr = a
>>> same_a = collection.class_a_ptr
>>> a.bitfield_member = 0
>>> print a.bitfield_member
0
>>> print same_a.bitfield_member
0
>>> same_a.bitfield_member = 1
>>> print a.bitfield_member
1
>>> print same_a.bitfield_member
1

关于c++ - 在 Boost.Python : wrong type 中的类中存储和检索指针时出现 ArgumentError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19461274/

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