Перегрузка — & gt; оператор для перенаправления членского доступа через прокси

Я пытаюсь завернуть питона PyObject* в Object учебный класс.
В Python все PyObject*,
Список является PyObject*и каждый элемент в списке сам по себе PyObject*,
Который может быть даже другой список.
и т.п.

Я пытаюсь разрешить fooList[42] = barObj синтаксис стиля с помощью шаблона Proxy (Вот).

Теперь, когда у меня это работает, я хочу расширить его так, чтобы 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’ предупреждение.

У меня внутри 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 соответственно.

Я сталкиваюсь с ‘получение адреса временного объекта типа Object’ предупреждение.

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 = ...
4

Другие решения

Я нахожу 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, так далее

1

После нескольких часов уговоров у меня есть рабочий тест.

Пожалуйста, обратитесь к: https://codereview.stackexchange.com/questions/75237/c11-proxy-pattern-for-supporting-obidx-someobjmember-type-acc

Большое спасибо Джароду за предоставленный правильный синтаксис и понимание -> перегрузки.

0
По вопросам рекламы [email protected]