Overload dereference operator in cython - overloading

In previous code, I receive an object of PPho and I want to retrieve the Pho object inside the shared pointer. How can I do that? I tried to access the shared_ptr directly, but it's private. I tried to dereference it twice. Then I tried to overload the dereference operator, but I was not successful (the error is also shown below).
C++ code (hpp):
class PPho {
private:
std::shared_ptr <Pho> PhoPtr;
public:
Pho *operator->() const;
PPho(const PPho &Other);
PPho(const std::shared_ptr <Pho> &Other);
PPho(std::nullptr_t);
PPho();
PPho &operator=(const PPho &Other);
PPho &operator=(const std::shared_ptr <Pho> &Other);
operator std::shared_ptr<Pho>() const;
operator std::weak_ptr<Pho>() const;
operator bool() const;
///Free the pointed resource and set the Pointer to nullptr.
void Reset();
class Pho{
Pho();
}
Cython header code I'm trying to use (pxd):
cdef cppclass Pho:
Pho()
Pho(Pho &Other)
cdef cppclass PPho:
PPho() except +
shared_ptr[Pho] PhoPtr
Pho *operator "*operator->()"
Cython code (pyx):
cdef class PyPPho:
cdef PPho* device
def __cinit__(self):
self.device = NULL
cdef assign_device(self, PPho& device_):
self.device = &device_
cdef get_pho(self):
return deref(self.device).get()
Error message:
cdef Get(self):
return deref(self.device).get()
^
------------------------------------------------------------
Ppho.pyx:43:33: Object of type 'PPho' has no attribute 'get'

Related

why is there a "no instance of overloaded function matches the argument list" error when attempting vector push_back?

I am doing an assignment for a C++ class and I am getting an error when using push back with vector. I honestly cannot find any info on why this isnt working and giving me a "no instance of overloaded function" error
class StudentData {
class StudyModule {
private:
const int studyModuleCode;
const std::string studyModuleName;
public:
StudyModule();
StudyModule(const StudyModule& copy);
~StudyModule();
};
private:
const int studentNumber;
std::string studentName;
std::vector<StudyModule*> modules;
public:
StudentData();
StudentData(const StudentData& copy);
~StudentData();
void addModules(const StudyModule& module);
int howManyModules();
};
void StudentData::addModules(const StudyModule& module)
{
this->modules.push_back(&module);
}
The function addModules() is declared like this:
void addModules(const StudyModule& module);
that is, its parameter is a reference to const object.
But the vector has a pointer to a non-const object as its template argument:
std::vector<StudyModule*> modules;
Thus, the compiler issues a message for this statement:
this->modules.push_back(&module);
because the expression &module has the type const StudyModule *, ie a pointer to a const object.
Even if you would change the template argument of the vector like this:
std::vector<const StudyModule *> modules;
your approach will be unsafe, because the user can pass a temporary object of type StudyModule to the function. In this case, storing a pointer to this object in the vector will become invalid when the temporary object is destroyed afterwards.

Overload -> operator to forward member-access through Proxy

I'm trying to wrap a Python PyObject* in an Object class.
In Python, everything is a PyObject*.
A list is a PyObject*, and each item in the list is itself a PyObject*.
Which could even be another list.
etc.
I'm trying to allow fooList[42] = barObj style syntax by means of a Proxy pattern (here).
Now that I have that working, I want to extend it so that fooList[42] can be used as an Object. Specifically I want to be able to handle...
fooList[42].myObjMethod()
fooList[42].myObjMember = ...
Object has a lot of methods, and currently fooList[42].myObjMethod() is going to first resolve fooList[42] into a Proxy instance, say tmpProxy, and then attempt tmpProxy.myObjMethod().
This means I would have to do
void Proxy::myObjMethod(){ return wrapped_ob.myObjMethod(); }
i.e. manually relay each of Object's methods through Proxy, which is ugly.
I can't see any perfect solution (see the above linked answer), but I would be happy to use:
fooList[42]->myObjMethod()
... as a compromise, seeing as -> can be overloaded (as opposed to . which cannot).
However, I can't find any documentation for overloading operator->.
My best guess is that it must return a pointer to some object (say pObj), and C++ will invoke pObj->whatever.
Below is my attempted implementation. However, I'm running into a 'taking the address of a temporary object of type Object' warning.
I have, within my Object class:
const Object operator[] (const Object& key) const {
return Object{ PyObject_GetItem( p, key.p ) };
}
NOTE that 'const Object&' runs into 'taking the address of a temporary object of type Object' warning.
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
};
The idea is to allow myList[5]->someMemberObj = ... style syntax.
myList[5] resolves as a Proxy instance, which is wrapping an Object (the sixth element of myList). Let's call it myItem.
Now I want someProxy->fooFunc() or someProxy->fooProperty to invoke myItem.fooFunc() or myItem.fooProperty respectively.
I'm running into a 'taking the address of a temporary object of type Object' warning.
If you can change Object, you may add
class Object {
public:
// other code
const Object* operator -> () const { return this; }
Object* operator -> () { return this; }
};
And for your Proxy
Object operator->() { return container[key]; }
So, for example
myObj[42]->myFoo = ...
is mostly equivalent to
Proxy proxy = myObj[42];
Object obj = proxy.operator ->();
Object* pobj = obj.operator ->(); // so pobj = &obj;
pobj->myFoo = ...
I find the Proxy class that you wrote as an example a bit confusing so i took the liberty to change it a little:
Here is a simple example:
//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]);
}
};
example usage:
CustomContainer cc;
cc[0]->foo();
cc[0]->bar("hello world");
cc[0]->foo();
As a design consideration the proxy class should be create in a controlled environment so constructors are removed from preventing miss-usage.
CustomContainer has to only return proxy_class with a reference to my_obj so it can use anything, std::map, std::vector, etc
After several hours of coaxing coliru, I have a working testcase.
Please refer to: https://codereview.stackexchange.com/questions/75237/c11-proxy-pattern-for-supporting-obidx-someobjmember-type-acc
Many thanks to Jarod, for supplying the correct syntax and understanding for -> overload.

How to use C++ operator[] in Cython?

I need to wrap a C++ class FooContainer defining the operator[]:
//foo.h:
#include <vector>
using namespace std;
struct Foo
{
Foo()
: value(42) {};
int value;
};
class FooContainer
{
public:
FooContainer() { this->values = vector<Foo> (100) ;}
Foo operator[](int i) {return values[i];}; // <-- the function I need to call
private:
vector<Foo> values;
};
I'm trying to write the corresponding .pyx file but whatever I try I can't figure out how to use Foo::operator
from cython.operator cimport dereference as deref
cdef extern from "foo.h":
cdef cppclass CppFoo "Foo":
pass
cdef extern from "foo.h":
cdef cppclass CppFooContainer "FooContainer":
FooContainer()
Foo operator[](int)
cdef class Foo:
cdef CppFoo * thisptr
cdef class FooContainer:
cdef CppFooContainer* thisptr
def __cinit__(self):
self.thisptr = new CppFooContainer ()
def __dealloc__(self):
if self.thisptr:
del self.thisptr
self.thisptr = <CppFooContainer*> 0
def __getitem__(self, int i):
cdef CppFoo f = deref(self.thisptr)[i] #just one out of many try
I'm probably missing the trivial solution but I always end up with the error: "Cannot convert Python object to 'CppFoo'". Which is the proper way to use the operator[] ?
The usage of operator[] is correct (Cython does not require special syntax for the array indexing operator), but
cdef extern from "foo.h":
cdef cppclass CppFooContainer "FooContainer":
FooContainer()
Foo operator[](int)
should be:
cdef extern from "foo.h":
cdef cppclass CppFooContainer "FooContainer":
CppFooContainer()
CppFoo operator[](int)
since FooContainer and Foo refer to the Python extension class types declared afterwards rather than the C++ class types from "foo.h".

Immutable object in collections (C++ and Qt)

I am stuck with using immutable objects with collections. Let assume I have the following class :
//in .h
class Data {
public:
Data(const DataObj& data);
Data(const Data&);
const DataObj& getDataObj() const;
private:
const DataObj _data; //actually several objects or simple type
}
inline const DataObj& Data::getDataObj() const {return _data};
//in .c
Data(const DataObj& data) : _data(data){};
Data(const Data& original) : _data(original._data){}
The issue is that when I want to use collections, I have the error
in member function Data&Data::operator(const Data&);
instantiation from 'typename QMap<Key,T>::iterator QMap<Key, T>::insert(const Key&, const T&)[with Key = int, T = Data]'
instantiation from here
error : non-static const member 'const DataObj Data::_data', can't use default assignment operator
Now defining an assignment operator doesn't seems to make sense, since its prototype will be
Data& operator=(const Data&);
What should I do? Am I forced to remove all constant qualifiers in order to use my class inside collections? Or use pointers?
If you are instantiating your map like this
QMap <MyKey, Data>
I guess you should always define an assignment operator for Data (default or your own).
You should try using pointers, as you suggest, like this
QMap <Mykey, Data*>
QMap <Mykey, QSharedPointer<Data>>
If you take a look to the QMap code http://code.woboq.org/kde/include/QtCore/qmap.h.html, some operators/members return < T >, so it would need assignment defined.
Use good stl containers instead of bad Qt:
This will fail to work with Qt container due to COW, but it ok (until you try to copy the container) with stl
class C
{
C operator=(const C&);
};
int main()
{
std::map<int, C> cc;
cc.insert(std::make_pair(0, C()));
}
You can make the data member non-const, but provide only const access to users of the class, except for the assignment operator:
class Data {
public:
Data(const DataObj& data);
Data(const Data&);
Data& operator=(const Data&);
const DataObj& getDataObj() const;
private:
DataObj _data;
};
In this way, assignment is the only operation that can mutate an existing object. You would then have to make sure you provide access to const instances of this type in any public interfaces.

const correctness with smart pointers

I'm trying to understand better how does const-correctness work and more specifically, when dealing with classes whose members are based on containers and smart pointers.
I guess that the const-correctness property is the same regardless of the class members. However, since I'm having some difficulties to clearly understand what's going on,
I decided to ask you for advice.
So, here is the context. I've a ShapeContainer class that has as private class member a vector of smart pointers.
The Shape class is abstract and has the following virtual function virtual float doSomething(); which is then redefined by its derived classes. Note that it's a non-const class function.
The relevant part of the code is given below:
class ShapeContainer{
public:
typedef std::shared_ptr<Shape> ShapePtr;
typedef std::vector<ShapePtr> ShapePtrContainer;
// .......
const ShapePtr & operator[]( int ) const { return m_vect[index]; }; // const version
// ShapePtr & operator[]( int ) { return m_vect[index]; }; // non-const version
// .......
private:
ShapePtrContainer m_vect;
};
class Shape{
public:
// ...
virtual float doSomething() = 0;
};
Here are my questions.
Q1. Why do I'm allowed to call the doSomething() function in the following way: int index = 0; float tmp = container1[index]->doSomething(); (having ShapeContainer container1=createBasicShapes();)?
From what I understand, after calling to the const ShapePtr operator[] const function we'll get a const pointer to a Shape object, however the doSomething() virtual
function is not const. So, how does a reference to a const-object can call a non-const function?
Q2. By calling the doSomething() function as previouly ilustrated (float tmp =container1[index]->doSomething();) and by adding a non-const version of the operator[], this latter
overloaded version is then called instead of the const-version one. Why does it is so?
Now, instead of having a ShapeContainer class, I've now a new class named ShapeContainerInfo that still has a vector but of an intermediate ShapeInfo class (that has a smart pointer as a class member).
class ShapeContainerInfo{
public:
typedef std::vector<ShapeInfo> ShapeContainer;
const ShapeInfo & operator []( int index) const { return m_vect[index]; };
// ShapeInfo & operator []( int index) { return m_vect[index]; }; // non-const version
private:
ShapeContainer m_vect;
};
class ShapeInfo{
public:
typedef std::shared_ptr<Shape> ShapePtr;
// ...
float doSomething(){ return m_ShapePtr->doSomething(); };
private:
ShapePtr m_ShapePtr;
int m_nID;
};
Q3. When I call float tmp = container2[i].doSomething();, I get the following compiler error: error C2662: 'ShapeInfo::doSomething' : cannot convert 'this' pointer from 'const ShapeInfo' to 'ShapeInfo &'.
However, when I add a non-const vesion of the overloaded operator [] the compiler error is gone. So, why do I really need the non-const operator[] for ShapeContainerInfo and not for ShapeContainer?
Q4. If the m_vect private member of ShapeContainerInfo is set now as public member and only the const-version of operator[] is defined (not the non-const one), there are no compiler error messages. Why this? e.g. after setting m_vect to be a public class member: float tmp = info.m_vect[i].doSomething();
Q5. How could I correctly define both the ShapeInfo and ShapeContainerInfo classes such that I only need to define the const-version of the operator[] and still being able to call the float doSomething() function?
For those of you interested in the whole sample code, please find it here.
Clarifications, suggestions are always welcomed :-)
Merci!
Q1: The shared_ptr is const, that doesn't mean that the pointed to object is const. For that you would want shared_ptr<const Shape>.
Q2: Since you're ShapeContainer was not const, the non-const function was a better match, so it was called instead of the const version.
Q3: vector propagates its constness to its elements. shared_ptr does not. This is inline with the behavior of arrays and raw pointers. The elements of const arrays are const. The thing pointed to by a const pointer is not (necessarily) const.
Q4: Are you saying this produces no error?
ShapeContainerInfo info;
info[0].doSomething();
Please clarify, because that should be an error.
Q4: Okay, so you're saying that this produces no error:
ShapeContainerInfo info;
info.m_vect[0].doSomething();
Nor should it. The vector is not const. It's only inside the const member function that the vector(and all other members) are treated as const.
Q5: Make m_vect a vector of unique pointers. Inside the const function, the vector itself will be const, and the unique pointers will be const. But the objects that the unique pointers point to will be mutable.
As an example, the set function in this class is not legal:
struct Foo
{
void set(int index, int value) const
{
v[index] = value;
}
std::vector<int> v;
};
But this one is:
struct Foo
{
void set(int index, int value) const
{
*v[index] = value;
}
std::vector<std::unique_ptr<int>> v;
};