我试图在PyObject*
类中包装Python Object
。
在Python中,一切都是PyObject*
。
列表是PyObject*
,列表中的每个项目本身都是PyObject*
。
哪个甚至可能是另一个列表。
等
我试图通过代理模式(here)来允许fooList[42] = barObj
样式语法。
现在我已经开始工作,我想扩展它,以便fooList[42]
可以用作Object
。具体来说,我希望能够处理......
fooList[42].myObjMethod()
fooList[42].myObjMember = ...
Object
有很多方法,目前fooList[42].myObjMethod()
首先将fooList[42]
解析为Proxy
个实例,比如tmpProxy
,然后再尝试tmpProxy.myObjMethod()
。
这意味着我必须这样做
void Proxy::myObjMethod(){ return wrapped_ob.myObjMethod(); }
即。通过Object
手动转发每个Proxy
的方法,这很丑陋。
我无法看到任何完美的解决方案(请参阅上面的链接答案),但我很乐意使用:
fooList[42]->myObjMethod()
...作为折衷方案,视为 - > 可以 重载(而不是.
,但不能)。
但是,我找不到任何重载operator->
的文档。
我最好的猜测是它必须返回指向某个对象的指针(比如说pObj
),而C ++会调用pObj->whatever
。
以下是我的尝试实施。但是,我遇到了一个'带着对象' 类型的临时对象的地址警告。
我在Object
课程中
const Object operator[] (const Object& key) const {
return Object{ PyObject_GetItem( p, key.p ) };
}
注意' const Object&'遇到'取一个Object' 类型的临时对象的地址。
class Proxy {
private:
const Object& container;
const Object& key;
public:
// at this moment we don't know whether it is 'c[k] = x' or 'x = c[k]'
Proxy( const Object& c, const Object& k ) : container{c}, key{k}
{ }
// Rvalue
// e.g. cout << myList[5] hits 'const Object operator[]'
operator Object() const {
return container[key];
}
// Lvalue
// e.g. (something = ) myList[5] = foo
const Proxy& operator= (const Object& rhs_ob) {
PyObject_SetItem( container.p, key.p, rhs_ob.p );
return *this; // allow daisy-chaining a = b = c etc, that's why we return const Object&
}
const Object* operator->() const { return &container[key]; }
// ^ ERROR: taking the address of a temporary object of type Object
};
这个想法是允许myList[5]->someMemberObj = ...
样式语法。
myList[5]
解析为Proxy
实例,其中包含Object
(myList
的第六个元素)。我们称之为myItem
。
现在我希望someProxy->fooFunc()
或someProxy->fooProperty
分别调用myItem.fooFunc()
或myItem.fooProperty
。
我遇到&#39;带着Object&#39; 类型的临时对象的地址警告。
答案 0 :(得分:4)
如果您可以更改Object
,则可以添加
class Object {
public:
// other code
const Object* operator -> () const { return this; }
Object* operator -> () { return this; }
};
适用于您的Proxy
Object operator->() { return container[key]; }
所以,例如
myObj[42]->myFoo = ...
大致相当于
Proxy proxy = myObj[42];
Object obj = proxy.operator ->();
Object* pobj = obj.operator ->(); // so pobj = &obj;
pobj->myFoo = ...
答案 1 :(得分:1)
我发现你写的Proxy
类作为一个例子有点令人困惑,所以我冒昧地改变了一点:
这是一个简单的例子:
//object with lots of members:
class my_obj
{
public:
std::string m_text;
void foo()
{
std::cout << m_text << std::endl;
}
void bar(std::string t)
{
m_text = t;
}
};
//proxy object
class proxy_class
{
private:
friend class CustomContainer;
my_obj* px;
proxy_class(my_obj * obj_px)
:px(obj_px)
{
}
proxy_class() = delete;
proxy_class(const proxy_class &) = delete;
proxy_class& operator =(const proxy_class &) = delete;
public:
my_obj* operator ->()
{
return px;
}
};
//custom container that is the only one that can return proxy objects
class CustomContainer
{
public:
std::map<std::size_t, my_obj> stuff;
proxy_class operator [](const std::size_t index)
{
return proxy_class(&stuff[index]);
}
};
示例用法:
CustomContainer cc;
cc[0]->foo();
cc[0]->bar("hello world");
cc[0]->foo();
作为设计考虑因素,代理类应该在受控环境中创建,这样可以避免构造函数阻止错误使用。
CustomContainer
必须仅返回proxy_class
并引用my_obj
,以便它可以使用任何内容,std::map
,std::vector
等
答案 2 :(得分:0)
经过几个小时的哄骗coliru,我有一个工作测试用例。
非常感谢Jarod,为 - &gt;提供正确的语法和理解。过载。