Hi, I would like to define an interface (abstract class) where one method is pure virtual and takes a std::function as a parameter. I have this in my C++ header ``` class MyInterface { public: #ifndef SIP_RUN virtual MyObject *doThings( const QString &filePath, const QUrl &url, const std::function<void ( const QString & )> &errorCallback = {} ) = 0 ; #else virtual MyObject *doThings( const QString &filePath, const QUrl &url, SIP_PYCALLABLE / AllowNone / ) = 0; % MethodCode { Py_BEGIN_ALLOW_THREADS sipCpp->MyInterface::doThings( *a0, *a1, [a2]( const QString & error ) { SIP_BLOCK_THREADS Py_XDECREF( sipCallMethod( NULL, a2, "D", &error, sipType_QString, NULL ) ); SIP_UNBLOCK_THREADS } ); sipRes = sipCpp; Py_END_ALLOW_THREADS } % End #endif ``` and this in the corresponding sip file ``` class MyInterface { %TypeHeaderCode #include "myinterface.h" %End public: virtual MyObject *doThings( const QString &filePath, const QUrl &url, SIP_PYCALLABLE / AllowNone / ) = 0; %MethodCode { Py_BEGIN_ALLOW_THREADS sipCpp->MyInterface::doThings( *a0, *a1, [a2]( const QString & error ) { SIP_BLOCK_THREADS Py_XDECREF( sipCallMethod( NULL, a2, "D", &error, sipType_QString, NULL ) ); SIP_UNBLOCK_THREADS } ); sipRes = sipCpp; Py_END_ALLOW_THREADS } %End }; ``` I end up with the following compilation errors ``` error: non-virtual member function marked 'override' hides virtual member function ::MyObject* doThings(const ::QString&,const ::QUrl&,PyObject *) SIP_OVERRIDE; hidden overloaded virtual function 'MyInterface::doThings' declared here: type mismatch at 3rd parameter ('const std::function<void (const QString &)> &' vs 'PyObject *' (aka '_object *')) virtual MyObject *doThings( const QString &filePath, const QUrl &url, ^ error: allocating an object of abstract class type 'sipMyInterface' sipCpp = new sipMyInterface(); ^ note: unimplemented pure virtual method 'doThings' in 'sipMyInterface' virtual MyObject *doThings( const QString &filePath, const QUrl &url, ``` The errors make sense to me because the sip doThings version has not the same signature than the original Cpp one (Callable vs std::function) but I fail to understand how to fix this. Kind regards, Julien |
Hi Julien, For the sake of clarity, you might want to filter out what is specific to QGIS syntax, mainly all the SIP_* macros. The sipify script is a QGIS internal and not known further. On Thu, 1 Apr 2021, 11:58 Julien Cabieces, <[hidden email]> wrote:
|
In reply to this post by jcabieces
On 01/04/2021 10:58, Julien Cabieces wrote:
> Hi, > > I would like to define an interface (abstract class) where one method > is > pure virtual and takes a std::function as a parameter. > > I have this in my C++ header > > ``` > class MyInterface > { > public: > > #ifndef SIP_RUN > virtual MyObject *doThings( const QString &filePath, const QUrl > &url, > const std::function<void ( const > QString & )> &errorCallback = {} ) = 0 ; > #else > virtual MyObject *doThings( const QString &filePath, const QUrl > &url, SIP_PYCALLABLE / AllowNone / ) = 0; > % MethodCode > { > Py_BEGIN_ALLOW_THREADS > > sipCpp->MyInterface::doThings( *a0, *a1, [a2]( const QString & > error ) > { > SIP_BLOCK_THREADS > Py_XDECREF( sipCallMethod( NULL, a2, "D", &error, > sipType_QString, NULL ) ); > SIP_UNBLOCK_THREADS > } ); > > sipRes = sipCpp; > > Py_END_ALLOW_THREADS > } > % End > #endif > ``` > > and this in the corresponding sip file > > ``` > class MyInterface > { > > %TypeHeaderCode > #include "myinterface.h" > %End > public: > > virtual MyObject *doThings( const QString &filePath, const QUrl > &url, SIP_PYCALLABLE / AllowNone / ) = 0; > %MethodCode > { > Py_BEGIN_ALLOW_THREADS > > sipCpp->MyInterface::doThings( *a0, *a1, [a2]( const QString & > error ) > { > SIP_BLOCK_THREADS > Py_XDECREF( sipCallMethod( NULL, a2, "D", &error, > sipType_QString, NULL ) ); > SIP_UNBLOCK_THREADS > } ); > > sipRes = sipCpp; > > Py_END_ALLOW_THREADS > } > %End > > }; > ``` > > I end up with the following compilation errors > > ``` > error: non-virtual member function marked 'override' hides virtual > member function > ::MyObject* doThings(const ::QString&,const ::QUrl&,PyObject *) > SIP_OVERRIDE; > > hidden overloaded virtual function 'MyInterface::doThings' declared > here: type mismatch at 3rd parameter ('const std::function<void (const > QString &)> &' vs 'PyObject *' (aka '_object *')) > virtual MyObject *doThings( const QString &filePath, const > QUrl &url, > ^ > error: allocating an object of abstract class type 'sipMyInterface' > sipCpp = new sipMyInterface(); > ^ > note: unimplemented pure virtual method 'doThings' in 'sipMyInterface' > virtual MyObject *doThings( const QString &filePath, const QUrl > &url, > ``` > > The errors make sense to me because the sip doThings version has not > the > same signature than the original Cpp one (Callable vs std::function) > but > I fail to understand how to fix this. You need to provide the C++ signature in [] after the Python signature. See the example in this section... https://www.riverbankcomputing.com/static/Docs/sip/directives.html#std-directive-VirtualCatcherCode ...and you need to provide %VirtualCatcherCode. Phil |
Hi, > You need to provide the C++ signature in [] after the Python signature. > See the example in this section... I change the signature in the sip file like this virtual MyObject *doThings( const QString &filePath, const QUrl &url, SIP_PYCALLABLE / AllowNone / ) = 0 [MyObject * ( const QString &, const QUrl &, const ErrorCallback & )]; and define the ErrorCallback this way in my header typedef std::function< void ( const QString & ) > ErrorCallback; It fails later with this error sip_corepart0.cpp:21379:193: error: unknown type name 'ErrorCallback' my header file is included later (line 49811) in cpp file produced by sip, so it's normal it doesn't know yet the ErrorCallback type. If I get rid of the typedef definition and put the std::function directly in the sip signature, sip fails with a syntax error. It looks like it comes from the parenthesis around "const QString &". Any idea? Regards, Julien > On 01/04/2021 10:58, Julien Cabieces wrote: >> Hi, >> >> I would like to define an interface (abstract class) where one method >> is >> pure virtual and takes a std::function as a parameter. >> >> I have this in my C++ header >> >> ``` >> class MyInterface >> { >> public: >> >> #ifndef SIP_RUN >> virtual MyObject *doThings( const QString &filePath, const QUrl >> &url, >> const std::function<void ( const >> QString & )> &errorCallback = {} ) = 0 ; >> #else >> virtual MyObject *doThings( const QString &filePath, const QUrl >> &url, SIP_PYCALLABLE / AllowNone / ) = 0; >> % MethodCode >> { >> Py_BEGIN_ALLOW_THREADS >> >> sipCpp->MyInterface::doThings( *a0, *a1, [a2]( const QString & >> error ) >> { >> SIP_BLOCK_THREADS >> Py_XDECREF( sipCallMethod( NULL, a2, "D", &error, >> sipType_QString, NULL ) ); >> SIP_UNBLOCK_THREADS >> } ); >> >> sipRes = sipCpp; >> >> Py_END_ALLOW_THREADS >> } >> % End >> #endif >> ``` >> >> and this in the corresponding sip file >> >> ``` >> class MyInterface >> { >> >> %TypeHeaderCode >> #include "myinterface.h" >> %End >> public: >> >> virtual MyObject *doThings( const QString &filePath, const QUrl >> &url, SIP_PYCALLABLE / AllowNone / ) = 0; >> %MethodCode >> { >> Py_BEGIN_ALLOW_THREADS >> >> sipCpp->MyInterface::doThings( *a0, *a1, [a2]( const QString & >> error ) >> { >> SIP_BLOCK_THREADS >> Py_XDECREF( sipCallMethod( NULL, a2, "D", &error, >> sipType_QString, NULL ) ); >> SIP_UNBLOCK_THREADS >> } ); >> >> sipRes = sipCpp; >> >> Py_END_ALLOW_THREADS >> } >> %End >> >> }; >> ``` >> >> I end up with the following compilation errors >> >> ``` >> error: non-virtual member function marked 'override' hides virtual >> member function >> ::MyObject* doThings(const ::QString&,const ::QUrl&,PyObject *) >> SIP_OVERRIDE; >> >> hidden overloaded virtual function 'MyInterface::doThings' declared >> here: type mismatch at 3rd parameter ('const std::function<void (const >> QString &)> &' vs 'PyObject *' (aka '_object *')) >> virtual MyObject *doThings( const QString &filePath, const >> QUrl &url, >> ^ >> error: allocating an object of abstract class type 'sipMyInterface' >> sipCpp = new sipMyInterface(); >> ^ >> note: unimplemented pure virtual method 'doThings' in 'sipMyInterface' >> virtual MyObject *doThings( const QString &filePath, const QUrl >> &url, >> ``` >> >> The errors make sense to me because the sip doThings version has not >> the >> same signature than the original Cpp one (Callable vs std::function) >> but >> I fail to understand how to fix this. > > You need to provide the C++ signature in [] after the Python signature. > See the example in this section... > > https://www.riverbankcomputing.com/static/Docs/sip/directives.html#std-directive-VirtualCatcherCode > > ...and you need to provide %VirtualCatcherCode. > > Phil |
In reply to this post by Denis Rouzaud
Hi Denis, > For the sake of clarity, you might want to filter out what is specific to > QGIS syntax, mainly all the SIP_* macros. > The sipify script is a QGIS internal and not known further. Indeed, I try to remove all the QGIS specifics, but I miss the SIP_* macros. Regards, Julien > Hi Julien, > > For the sake of clarity, you might want to filter out what is specific to > QGIS syntax, mainly all the SIP_* macros. > The sipify script is a QGIS internal and not known further. > > > On Thu, 1 Apr 2021, 11:58 Julien Cabieces, <[hidden email]> > wrote: > >> >> Hi, >> >> I would like to define an interface (abstract class) where one method is >> pure virtual and takes a std::function as a parameter. >> >> I have this in my C++ header >> >> ``` >> class MyInterface >> { >> public: >> >> #ifndef SIP_RUN >> virtual MyObject *doThings( const QString &filePath, const QUrl &url, >> const std::function<void ( const QString & >> )> &errorCallback = {} ) = 0 ; >> #else >> virtual MyObject *doThings( const QString &filePath, const QUrl &url, >> SIP_PYCALLABLE / AllowNone / ) = 0; >> % MethodCode >> { >> Py_BEGIN_ALLOW_THREADS >> >> sipCpp->MyInterface::doThings( *a0, *a1, [a2]( const QString & >> error ) >> { >> SIP_BLOCK_THREADS >> Py_XDECREF( sipCallMethod( NULL, a2, "D", &error, sipType_QString, >> NULL ) ); >> SIP_UNBLOCK_THREADS >> } ); >> >> sipRes = sipCpp; >> >> Py_END_ALLOW_THREADS >> } >> % End >> #endif >> ``` >> >> and this in the corresponding sip file >> >> ``` >> class MyInterface >> { >> >> %TypeHeaderCode >> #include "myinterface.h" >> %End >> public: >> >> virtual MyObject *doThings( const QString &filePath, const QUrl &url, >> SIP_PYCALLABLE / AllowNone / ) = 0; >> %MethodCode >> { >> Py_BEGIN_ALLOW_THREADS >> >> sipCpp->MyInterface::doThings( *a0, *a1, [a2]( const QString & >> error ) >> { >> SIP_BLOCK_THREADS >> Py_XDECREF( sipCallMethod( NULL, a2, "D", &error, sipType_QString, >> NULL ) ); >> SIP_UNBLOCK_THREADS >> } ); >> >> sipRes = sipCpp; >> >> Py_END_ALLOW_THREADS >> } >> %End >> >> }; >> ``` >> >> I end up with the following compilation errors >> >> ``` >> error: non-virtual member function marked 'override' hides virtual member >> function >> ::MyObject* doThings(const ::QString&,const ::QUrl&,PyObject *) >> SIP_OVERRIDE; >> >> hidden overloaded virtual function 'MyInterface::doThings' declared here: >> type mismatch at 3rd parameter ('const std::function<void (const QString >> &)> &' vs 'PyObject *' (aka '_object *')) >> virtual MyObject *doThings( const QString &filePath, const QUrl >> &url, >> ^ >> error: allocating an object of abstract class type 'sipMyInterface' >> sipCpp = new sipMyInterface(); >> ^ >> note: unimplemented pure virtual method 'doThings' in 'sipMyInterface' >> virtual MyObject *doThings( const QString &filePath, const QUrl &url, >> ``` >> >> The errors make sense to me because the sip doThings version has not the >> same signature than the original Cpp one (Callable vs std::function) but >> I fail to understand how to fix this. >> >> Kind regards, >> Julien >> |
In reply to this post by jcabieces
On 06/04/2021 13:24, Julien Cabieces wrote:
> Hi, > >> You need to provide the C++ signature in [] after the Python >> signature. >> See the example in this section... > > I change the signature in the sip file like this > > virtual MyObject *doThings( const QString &filePath, const QUrl &url, > SIP_PYCALLABLE / AllowNone / ) = 0 [MyObject * ( const QString &, const > QUrl &, const ErrorCallback & )]; > > and define the ErrorCallback this way in my header > > typedef std::function< void ( const QString & ) > ErrorCallback; > > It fails later with this error > > sip_corepart0.cpp:21379:193: error: unknown type name 'ErrorCallback' > > my header file is included later (line 49811) in cpp file produced by > sip, so it's normal it doesn't know yet the ErrorCallback type. > > If I get rid of the typedef definition and put the std::function > directly in the sip signature, sip fails with a syntax error. It looks > like it comes from the parenthesis around "const QString &". > > Any idea? SIP doesn't implement a full C++ parser and there will be some constructs that it can't handle, in this case the arguments to the std::function template. (Maybe putting a dummy name after the void would work.) A separate issue might be that SIP is being too aggressive when parsing the C++ signature and maybe it could/should not try to resolve ErrorCallback and leave it to the C++ compiler to determine if it has a proper definition. For the moment I can't suggest anything other than not using std::function. Phil |
Hi, Thank you for your reponse, I'm gonna considering doing it an other way. Regards, Julien > On 06/04/2021 13:24, Julien Cabieces wrote: >> Hi, >> >>> You need to provide the C++ signature in [] after the Python >>> signature. >>> See the example in this section... >> >> I change the signature in the sip file like this >> >> virtual MyObject *doThings( const QString &filePath, const QUrl &url, >> SIP_PYCALLABLE / AllowNone / ) = 0 [MyObject * ( const QString &, const >> QUrl &, const ErrorCallback & )]; >> >> and define the ErrorCallback this way in my header >> >> typedef std::function< void ( const QString & ) > ErrorCallback; >> >> It fails later with this error >> >> sip_corepart0.cpp:21379:193: error: unknown type name 'ErrorCallback' >> >> my header file is included later (line 49811) in cpp file produced by >> sip, so it's normal it doesn't know yet the ErrorCallback type. >> >> If I get rid of the typedef definition and put the std::function >> directly in the sip signature, sip fails with a syntax error. It looks >> like it comes from the parenthesis around "const QString &". >> >> Any idea? > > SIP doesn't implement a full C++ parser and there will be some > constructs that it can't handle, in this case the arguments to the > std::function template. (Maybe putting a dummy name after the void would > work.) > > A separate issue might be that SIP is being too aggressive when parsing > the C++ signature and maybe it could/should not try to resolve > ErrorCallback and leave it to the C++ compiler to determine if it has a > proper definition. > > For the moment I can't suggest anything other than not using > std::function. > > Phil |
Free forum by Nabble | Edit this page |