2

I am trying to use a non-static method as callback method for qmlRegisterSingletonType in Qt 5. My code looks like this:

PersistentLong couponCounter("couponCounter", handler.getSubjectRunner(), handler.getDbManager());

qmlRegisterSingletonType<PersistentLong>("MyNamespace", 1, 0, "CouponCounter", couponCounter.factory);

But I get the following compiler error:

/.../src/Main.cxx: In function ‘int main(int, char**)’:
/.../src/Main.cxx:22:102: error: no matching function for call to ‘qmlRegisterSingletonType(const char [9], int, int, const char [14], <unresolved overloaded function type>)’
     qmlRegisterSingletonType<PersistentLong>("MyNamespace", 1, 0, "CouponCounter", couponCounter.factory);
                                                                                                  ^
/.../src/Main.cxx:22:102: note: candidate is:
In file included from /usr/local/Qt-5.3.2/include/QtQml/QtQml:9:0,
                 from /.../src/Main.cxx:6:
/usr/local/Qt-5.3.2/include/QtQml/qqml.h:476:12: note: template<class T> int qmlRegisterSingletonType(const char*, int, int, const char*, QObject* (*)(QQmlEngine*, QJSEngine*))
 inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName,
            ^
/usr/local/Qt-5.3.2/include/QtQml/qqml.h:476:12: note:   template argument deduction/substitution failed:
/.../src/Main.cxx:22:102: note:   cannot convert ‘couponCounter.PersistentLong::factory’ (type ‘<unresolved overloaded function type>’) to type ‘QObject* (*)(QQmlEngine*, QJSEngine*)’
     qmlRegisterSingletonType<PersistentLong>("MyNamespace", 1, 0, "CouponCounter", couponCounter.factory);

The factory method of PersistentLong looks like this:

QObject * factory(QQmlEngine *engine, QJSEngine *scriptEngine) {
    Q_UNUSED(engine)
    Q_UNUSED(scriptEngine)

    return this;
}

Questions

Any ideas as to why I can't use this method as argument to qmlRegisterSingletonType?

Is there another way to register a non-static instance as a singleton in QML?

Edit 1

couponCounter is constructed in main() in the following way:

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QtSubjectHandler handler("burgundy_frontend");

    PersistentLong couponCounter("couponCounter", handler.getSubjectRunner(), handler.getDbManager());

    qmlRegisterSingletonType<PersistentLong>("MyNamespace", 1, 0, "CouponCounter", couponCounter.factory);
}

If I use a function pointer, how can I reference couponCounter in this function?

uldall
  • 2,458
  • 1
  • 17
  • 31
  • as I understand `couponCounter` is a function, how can you access the function in this way - `couponCounter.factory`? May be it have to be `couponCounter().factory` or `PersistentLong::couponCounter`? – folibis Nov 05 '14 at 23:18

1 Answers1

1

Any ideas as to why I can't use this method as argument to qmlRegisterSingletonType?

Given the usage of the factory method, I can guess it is a member function of the class what you are using as a callback. However, the registration function has the following signature:

int qmlRegisterSingletonType(const char * uri, int versionMajor, int versionMinor, const char * typeName, QObject *(* ) ( QQmlEngine *, QJSEngine * ) callback)

As you can see the last parameter is a function pointer but you are (trying to) pass a pointer to a member function which is quite different. Note that neither a friend function nor a static function could be exploited in this case, since both of them lack the access to the this pointer.

Is there another way to register a non-static instance as a singleton in QML?

It is perfectly feasable to write and compile a global function like this (static, where are you?):

QObject *provider(QQmlEngine *engine, QJSEngine *scriptEngine)
{
    Q_UNUSED(engine)
    Q_UNUSED(scriptEngine)
    return new MyNiceObject();
}

and register it like this:

qmlRegisterSingletonType<AppInfo>("AppInfo", 1, 0, "AppInfo", provider);

Digia examples uses this approach, apart from the static I've removed. Unfortunately, documentation is quite vague and do not provide a specific reason for using a static modifier so the only reason I can think about is visibility purposes. Anyone more informed/skilled can correct me if I'm wrong and tell us if there is a more specific/thought reason (e.g. any specific memory management reason).

In the end, the whole point is to provide the QML Engine with a function which creates the instance of our type and such a result cannot be achieved with a member function.

On a side note, if you prefer to return also a singleton instance, you can exploit the singleton pattern (which again uses the static modifier) and rewrite the function like this:

 QObject *provider(QQmlEngine *engine, QJSEngine *scriptEngine)
{
    Q_UNUSED(engine)
    Q_UNUSED(scriptEngine)
    MyNiceObject * p = MyNiceObject::instance();    // uhmmmm static...
    QQmlEngine::setObjectOwnership(p, QQmlEngine::CppOwnership);
    return p;
}

Note that the ownership of the created object is given to the QML engine by default. to avoid the problem the QQmlEngine::setObjectOwnership() call can be used.

Community
  • 1
  • 1
BaCaRoZzo
  • 7,502
  • 6
  • 51
  • 82
  • I am not sure how to reference `couponCounter` if I use a function pointer. How can I get a reference to an object created in main() in such a function? See my edit to the original question. – uldall Nov 06 '14 at 08:10
  • 1
    That's a *third* question, actually. You should really take in account `setObjectOwnership()` if you want to be sure your instance is not deleted. Apart from that, with my current lack of knowledge about the internals of the engine, is it difficult to say how to properly set an object created in the main. My Apologizes. – BaCaRoZzo Nov 06 '14 at 09:52