5

PyObject*PythonをObjectクラスにラップしようとしています。Python では、すべてがPyObject*. リストは でありPyObject*、リスト内の各項目自体がPyObject*です。これは別のリストになる可能性さえあります。等

fooList[42] = barObjProxy パターン ( here ) を使用してスタイル構文を許可しようとしています。

fooList[42]これで機能するようになったので、拡張してとして使用できるようにしたいと思いObjectます。具体的には対応できるようになりたい...

fooList[42].myObjMethod()
fooList[42].myObjMember = ...

Objectには多くのメソッドがあり、現在、最初に をインスタンスにfooList[42].myObjMethod()解決fooList[42]し、次に を試みます。ProxytmpProxytmpProxy.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&」は、「オブジェクト型の一時オブジェクトのアドレスを取得する」という警告に遭遇することに注意してください。

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]( の 6 番目の要素)Proxyをラップするインスタンスとして解決されます。と呼びましょう。ObjectmyListmyItem

今、私は、またはsomeProxy->fooFunc()それぞれsomeProxy->fooPropertyを呼び出したいです。myItem.fooFunc()myItem.fooProperty

「オブジェクト型の一時オブジェクトのアドレスを取得しています」という警告が表示されます。

4

3 に答える 3

5

変更できる場合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 = ...
于 2014-12-29T12:54:59.467 に答える
2

あなたが例として書いたクラスは少しわかり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();

設計上の考慮事項として、プロキシ クラスは制御された環境で作成する必要があります。これにより、コンストラクターが誤用を防ぐことができなくなります。

CustomContainerproxy_classへの参照のみを返す必要があるため、、 などmy_obj何でも使用できますstd::mapstd::vector

于 2014-12-29T14:56:18.013 に答える
1

コリールを数時間説得した後、動作するテストケースができました。

参照してください: https://codereview.stackexchange.com/questions/75237/c11-proxy-pattern-for-supporting-obidx-someobjmember-type-acc

-> オーバーロードの正しい構文と理解を提供してくれた Jarod に感謝します。

于 2014-12-29T23:45:36.030 に答える