如何使用 cppyy 从指针索引 类 数组
How do I index array of classes from a pointer with cppyy
我看过有关 cppyy 中基本类型的数组索引的文档。我还没有想出如何索引自定义类型的数组。
参加:
import cppyy
cppyy.cppdef("""
struct Foo
{
float var;
}
struct Bar
{
Foo* foo;
}
""")
如果 Foo
对象的数组存储在 Bar
的实例中,我如何索引该数组以访问 Foo
元素?
如果我尝试:
bar.foo[0]
我得到:
'Foo' object does not support indexing
编辑 2:根据您在下面评论中的建议,原始代码现在可以在 cppyy 1.6.2 版中开箱即用。也就是说,如果 Python 代理包含一个指针类型,那么索引被认为是表示它代表一个数组。
原样 Foo*
被当作指向 Foo
的指针,而不是 Foo
的数组。是的,它 可以 指向一个数组,但是低级 C++(实际上是 C)是模棱两可的,它是一个指向对象的指针是迄今为止常见的情况。如果某物是数组,数组语法确实有效,因为它再次变得明确:
import cppyy
cppyy.cppdef("""
struct Foo
{
float var;
};
struct Bar
{
Foo foo[1];
};
""")
bar = cppyy.gbl.Bar()
print(len(bar.foo))
print(bar.foo[0])
打印:
1
<cppyy.gbl.Foo object at 0x7f85ace370f0>
符合预期。
如果您不知道数组的长度,是否有任何选项可以让您使用 std::unique_ptr 等现代 C++ 结构来代替传统的 C?这些是完全明确的,因此很容易自动绑定(它们也使内存管理更容易):
import cppyy
cppyy.cppdef("""
struct Foo
{
float var;
};
struct Bar
{
Bar(int num_foo) : foo(std::unique_ptr<Foo[]>{new Foo[num_foo]}) {
for (int i = 0; i < num_foo; ++i)
foo[i].var = (float)2.*i;
}
std::unique_ptr<Foo[]> foo;
};
""")
num_foo = 4
bar = cppyy.gbl.Bar(num_foo)
for i in range(num_foo):
print(bar.foo[i].var)
打印预期的:
0.0
2.0
4.0
6.0
如果您确实处于维护遗留代码的尴尬境地,我建议您使用 C++(通过带有 cppdef 的 JIT)和 Python 帮助程序(有关 Python 化的更多详细信息,请参见此处:https://cppyy.readthedocs.io/en/latest/pythonizations.html).例如:
import cppyy
cppyy.cppdef("""
struct Foo
{
float var;
};
struct Bar
{
Bar() : foo(new Foo{}) { foo[0].var = 42.f; }
// memory mgmt here ...
Foo* foo;
};
Foo* Bar_get_foo_indexed(Bar* b, int idx) {
return &b->foo[idx];
}
""")
# pythonize the getter
class FooGetter(object):
def __get__(self, obj, kls=None):
self.obj = obj
return self
def __getitem__(self, idx):
return cppyy.gbl.Bar_get_foo_indexed(self.obj, idx)
cppyy.gbl.Bar.foo = FooGetter()
bar = cppyy.gbl.Bar()
print(bar.foo[0].var)
打印预期的:
42.0
编辑:根据您的问题提出更多想法。首先是 C++ 端的转换示例:
cppyy.cppdef("""
struct Foo
{
float var;
};
struct Bar
{
Bar() : foo(new Foo[2]) { foo[0].var = 42.f; foo[1].var = 13.f; }
// memory mgmt here ...
Foo* foo;
};
template<int N>
struct FooArrayWrapper {
Foo foo[N];
};
template<int N>
FooArrayWrapper<N>* cast_foo_array(Foo*& f) {
return reinterpret_cast<FooArrayWrapper<N>*>(f);
}
""")
def make_foo_wrapper_init(func):
def wrapper_init(self, foo_size, *args, **kwargs):
func(self)
self.__dict__['foo_array'] = cppyy.gbl.cast_foo_array[foo_size](self.foo).foo
return wrapper_init
cppyy.gbl.Bar.__init__ = make_foo_wrapper_init(cppyy.gbl.Bar.__init__)
bar = cppyy.gbl.Bar(2)
print(bar.foo_array[0].var)
print(bar.foo_array[1].var)
以及在 Python 端使用指针算法的转换示例:
cppyy.cppdef("""
struct Foo
{
float var;
};
struct Bar
{
Bar() : foo(new Foo[2]) { foo[0].var = 42.f; foo[1].var = 13.f; }
// memory mgmt here ...
Foo* foo;
};
""")
bar = cppyy.gbl.Bar()
for i in range(2):
print(cppyy.bind_object(cppyy.addressof(bar.foo)+i*cppyy.sizeof(cppyy.gbl.Foo), cppyy.gbl.Foo).var)
都打印预期的:
42.0
13.0
我看过有关 cppyy 中基本类型的数组索引的文档。我还没有想出如何索引自定义类型的数组。
参加:
import cppyy
cppyy.cppdef("""
struct Foo
{
float var;
}
struct Bar
{
Foo* foo;
}
""")
如果 Foo
对象的数组存储在 Bar
的实例中,我如何索引该数组以访问 Foo
元素?
如果我尝试:
bar.foo[0]
我得到:
'Foo' object does not support indexing
编辑 2:根据您在下面评论中的建议,原始代码现在可以在 cppyy 1.6.2 版中开箱即用。也就是说,如果 Python 代理包含一个指针类型,那么索引被认为是表示它代表一个数组。
原样 Foo*
被当作指向 Foo
的指针,而不是 Foo
的数组。是的,它 可以 指向一个数组,但是低级 C++(实际上是 C)是模棱两可的,它是一个指向对象的指针是迄今为止常见的情况。如果某物是数组,数组语法确实有效,因为它再次变得明确:
import cppyy
cppyy.cppdef("""
struct Foo
{
float var;
};
struct Bar
{
Foo foo[1];
};
""")
bar = cppyy.gbl.Bar()
print(len(bar.foo))
print(bar.foo[0])
打印:
1
<cppyy.gbl.Foo object at 0x7f85ace370f0>
符合预期。
如果您不知道数组的长度,是否有任何选项可以让您使用 std::unique_ptr 等现代 C++ 结构来代替传统的 C?这些是完全明确的,因此很容易自动绑定(它们也使内存管理更容易):
import cppyy
cppyy.cppdef("""
struct Foo
{
float var;
};
struct Bar
{
Bar(int num_foo) : foo(std::unique_ptr<Foo[]>{new Foo[num_foo]}) {
for (int i = 0; i < num_foo; ++i)
foo[i].var = (float)2.*i;
}
std::unique_ptr<Foo[]> foo;
};
""")
num_foo = 4
bar = cppyy.gbl.Bar(num_foo)
for i in range(num_foo):
print(bar.foo[i].var)
打印预期的:
0.0
2.0
4.0
6.0
如果您确实处于维护遗留代码的尴尬境地,我建议您使用 C++(通过带有 cppdef 的 JIT)和 Python 帮助程序(有关 Python 化的更多详细信息,请参见此处:https://cppyy.readthedocs.io/en/latest/pythonizations.html).例如:
import cppyy
cppyy.cppdef("""
struct Foo
{
float var;
};
struct Bar
{
Bar() : foo(new Foo{}) { foo[0].var = 42.f; }
// memory mgmt here ...
Foo* foo;
};
Foo* Bar_get_foo_indexed(Bar* b, int idx) {
return &b->foo[idx];
}
""")
# pythonize the getter
class FooGetter(object):
def __get__(self, obj, kls=None):
self.obj = obj
return self
def __getitem__(self, idx):
return cppyy.gbl.Bar_get_foo_indexed(self.obj, idx)
cppyy.gbl.Bar.foo = FooGetter()
bar = cppyy.gbl.Bar()
print(bar.foo[0].var)
打印预期的:
42.0
编辑:根据您的问题提出更多想法。首先是 C++ 端的转换示例:
cppyy.cppdef("""
struct Foo
{
float var;
};
struct Bar
{
Bar() : foo(new Foo[2]) { foo[0].var = 42.f; foo[1].var = 13.f; }
// memory mgmt here ...
Foo* foo;
};
template<int N>
struct FooArrayWrapper {
Foo foo[N];
};
template<int N>
FooArrayWrapper<N>* cast_foo_array(Foo*& f) {
return reinterpret_cast<FooArrayWrapper<N>*>(f);
}
""")
def make_foo_wrapper_init(func):
def wrapper_init(self, foo_size, *args, **kwargs):
func(self)
self.__dict__['foo_array'] = cppyy.gbl.cast_foo_array[foo_size](self.foo).foo
return wrapper_init
cppyy.gbl.Bar.__init__ = make_foo_wrapper_init(cppyy.gbl.Bar.__init__)
bar = cppyy.gbl.Bar(2)
print(bar.foo_array[0].var)
print(bar.foo_array[1].var)
以及在 Python 端使用指针算法的转换示例:
cppyy.cppdef("""
struct Foo
{
float var;
};
struct Bar
{
Bar() : foo(new Foo[2]) { foo[0].var = 42.f; foo[1].var = 13.f; }
// memory mgmt here ...
Foo* foo;
};
""")
bar = cppyy.gbl.Bar()
for i in range(2):
print(cppyy.bind_object(cppyy.addressof(bar.foo)+i*cppyy.sizeof(cppyy.gbl.Foo), cppyy.gbl.Foo).var)
都打印预期的:
42.0
13.0