重载 -> 运算符通过代理转发成员访问

P i*_*P i 5 c++ operator-overloading proxy-pattern c++11

我正在尝试将 Python 包装PyObject*在一个Object类中。在 Python 中,一切都是PyObject*. 列表是 a PyObject*,列表中的每一项本身就是 a PyObject*。这甚至可能是另一个列表。等等。

我试图fooList[42] = barObj通过代理模式(here)来允许样式语法。

现在我已经可以工作了,我想扩展它,以便fooList[42]可以将其用作Object. 具体来说,我希望能够处理...

fooList[42].myObjMethod()
fooList[42].myObjMember = ...
Run Code Online (Sandbox Code Playgroud)

Object有很多方法,目前fooList[42].myObjMethod()将首先解析fooList[42]为一个Proxy实例,比如tmpProxy,然后尝试tmpProxy.myObjMethod()

这意味着我将不得不做

void Proxy::myObjMethod(){ return wrapped_ob.myObjMethod(); }
Run Code Online (Sandbox Code Playgroud)

即通过 手动中继每个Object方法Proxy,这很丑陋。

我看不到任何完美的解决方案(请参阅上面链接的答案),但我很乐意使用:

fooList[42]->myObjMethod()
Run Code Online (Sandbox Code Playgroud)

... 作为妥协,将 as -> 视为可以重载(而不是.不能)。

但是,我找不到任何有关重载的文档operator->

我最好的猜测是它必须返回一个指向某个对象的指针(比如pObj),而 C++ 将调用pObj->whatever.


下面是我尝试的实现。但是,我遇到了“获取对象类型的临时对象的地址”警告。

我有,在我的Object班级:

const Object operator[] (const Object& key)     const { 
    return Object{ PyObject_GetItem( p, key.p ) }; 
}
Run Code Online (Sandbox Code Playgroud)

请注意,“const 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
};
Run Code Online (Sandbox Code Playgroud)

这个想法是允许myList[5]->someMemberObj = ...样式语法。

myList[5]解析为一个Proxy实例,它包装 an Object( 的第六个元素myList)。让我们称之为myItem

现在,我想someProxy->fooFunc()还是someProxy->fooProperty要调用myItem.fooFunc()myItem.fooProperty分别。

我遇到了“获取对象类型的临时对象的地址”警告。

Jar*_*d42 5

如果你可以改变Object,你可以添加

class Object {
public:
    // other code
    const Object* operator -> () const { return this; }
    Object* operator -> () { return this; }
};
Run Code Online (Sandbox Code Playgroud)

而对于你 Proxy

Object operator->() { return container[key]; }
Run Code Online (Sandbox Code Playgroud)

所以,例如

myObj[42]->myFoo = ...
Run Code Online (Sandbox Code Playgroud)

主要相当于

Proxy proxy = myObj[42];
Object obj = proxy.operator ->();
Object* pobj = obj.operator ->(); // so pobj = &obj;
pobj->myFoo = ...
Run Code Online (Sandbox Code Playgroud)