Я пытаюсь завернуть питона 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’ предупреждение.
Если вы можете изменить 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 = ...
Я нахожу 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
, так далее
После нескольких часов уговоров у меня есть рабочий тест.
Пожалуйста, обратитесь к: https://codereview.stackexchange.com/questions/75237/c11-proxy-pattern-for-supporting-obidx-someobjmember-type-acc
Большое спасибо Джароду за предоставленный правильный синтаксис и понимание -> перегрузки.