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