SIP: Virtual pure method with std::function

Julien Cabieces julien.cabieces at oslandia.com
Tue Apr 6 13:24:26 BST 2021


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



More information about the PyQt mailing list