Cython and c++ class constructors

痴心易碎 提交于 2020-01-01 06:07:08

问题


Can someone suggest a way to manipulate c++ objects with Cython, when the c++ instance of one class is expected to feed the constructor of another wrapped class as described below?

Please look at the note on the pyx file for the class PySession, which takes a python PyConfigParams object as argument and then needs to extract values from it in order to construct a c++ ConfigParams object. the ConfigParams object is then used to feed the constructor of Session.

It would be ideal to have a procedure which would allow me to "inject" the ConfigParams c++ object wrapped by the PyConfigParams object directly into the constructor of Session, without having to dismantle it first and then building a new c++ object to feed the constructor. This works, of course. However, it is a cumbersome, sort of brutal way to implement this solution, not to mention unreliable.

I am aware of PyCapsule, however it may require to touch the c++ headers, which is something I can not do.

Related to this, but a different question is: what if I need a wrapped class (let's say here PySession) to simulate the behavior of the C++ api by returning a ConfigParams instance? would I need to do the reverse and dismantle the c++ object to build a Python PyConfigParams which would then be returned to the Python user in the Python world? Any suggestions are very welcome! Thank you!

Let's suppose I have two c++ classes named ConfigParams and Session. An instance of ConfigParams is used to feed the constructor of the Session class:

C++ classes

ConfigParams class

// ConfigParams.h
#include <iostream> 
using namespace std; 
class ConfigParams 
{ 
  int parameter1; 
 public: 
  ConfigParams(int par1) { this->parameter1 = par1;} 
  int getPar1() { return this->parameter1; } 
};

Session class

// Session.h 
#include <iostream> 
using namespace std; 
#include "configparams.h" 
class Session 
{ 
  int sessionX; 
 public: 
  Session(ConfigParams parameters) { this->sessionX = parameters.getPar1(); } 
  void doSomething(); 
}; 

void Session::doSomething() 
{ 
  cout << "Session parameters set as: " << endl; 
  cout << "X = " << this->sessionX << endl; 
} 

Cython pyx and pxd files for the above classes:

PyConfigParams

# configparams.pxd 
cdef extern from "configparams.h": 
    cppclass ConfigParams: 
        ConfigParams(int par1) 
        int getPar1() 

# configparams.pyx 
cdef class PyConfigParams: 
    cdef ConfigParams* thisptr 
    def __cinit__(self, i): 
        self.thisptr = new ConfigParams(<int> i) 
    def getPar1(self): 
        return self.thisptr.getPar1() 

PySession class

# session.pxd 
from configparams cimport * 
cdef extern from "session.h": 
    cdef cppclass Session: 
        Session(ConfigParams parameters) 
        void doSomething() 

# session.pyx
cdef class PySession: 
    cdef Session* thisptr 
    def __cinit__(self, pars): 
        # Note that here I have to extract the values 
        # from the pars (python PyConfigParams object) 
        # in order to build a c++ ConfigParams object 
        # which feeds the c ++ constructor of Session. 
        cdef ConfigParams* cpppargsptr = new ConfigParams(<int> pars.getPar1()) 
        self.thisptr = new Session(cpppargsptr[0]) 
    def doSomething(self): 
        self.thisptr.doSomething() 

回答1:


Solution:

Forward declare PyConfigParams in the configparams.pxd module (so it can be invoked from the session.pyx module)

# configparams.pxd                                                                                                                                                                                                                                            
cdef extern from "configparams.h":
    cppclass ConfigParams:
        ConfigParams(int par1)
        int getPar1()

cdef class PyConfigParams:
    cdef ConfigParams* thisptr

Import PyConfigParams in the session.pyx module, and cast the argument for the constuctor, this will grant access to the PyConfigParams pointer to the c++ object, which will need to be dereferenced.

# session.pyx                                                                                                                                                                                                                                                 
from configparams cimport PyConfigParams
from cython.operator cimport dereference as deref

cdef class PySession:
    cdef Session* thisptr
    def __cinit__(self, PyConfigParams pars):
        self.thisptr = new Session(deref(pars.thisptr))
    def doSomething(self):
        self.thisptr.doSomething()


来源:https://stackoverflow.com/questions/10436837/cython-and-c-class-constructors

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!