[SOLVED] How to write Q_INVOKABLE function with optional parameter?

Issue

Here is my C++ function

header file:

Q_INVOKABLE void setSelection(qint64 start, qint64 end, qint64 init);

body file:

void SelectionModel::setSelection(qint64 start, qint64 end, qint64 init) { 
    ...
}

How can I modify the init parameter into an optional parameter so that

A)

I can call the function from JavaScript as either of:

setSelection(0, 10, 4)
setSelection(0, 10)

B)

I can find out in the C++ code whether the init parameter has been passed or not.

Solution

The 2 other answers are good. The main point is that you cannot know in C++ if a default parameter has been passed or not.

Sometimes you can sacrifice some parts of the range of the used type to detect a default value: void f(int somethingThatShouldBePositive = -1).

With C++17, we now have a new mechanism to handle such cases without sacrificing range:

void f(std::optional<int> a = std::optional<int>()) {
    if (!a.has_value()) {
         // f was called like this: f()
    } else {
        // f was called like this f(-1) or f(10)
    }
}

However, it does not work with QML (or Qt Meta Type System), so you need to wrap it:

Q_INVOKABLE void f(int a, int b) {
    qDebug() << Q_FUNC_INFO;
    f(a, b, std::optional<int>{});
}
Q_INVOKABLE void f(int a, int b, int c) {
    qDebug() << Q_FUNC_INFO << a << b << c;
    f(a, b, std::optional<int>{ c });
}
Q_INVOKABLE void f(int a, int b, std::optional<int> c){
    qDebug() << Q_FUNC_INFO << a << b << c.has_value();
}

Calling from QML:

        obj.f(1,1);
        obj.f(1,2,3);

Produces the following output:

void __cdecl Object::f(int,int)
void __cdecl Object::f(int,int,class std::optional<int>) 1 1 false
void __cdecl Object::f(int,int,int) 1 2 3
void __cdecl Object::f(int,int,class std::optional<int>) 1 2 true

This is exactly what you want, but I would only recommend doing so if and only if the other answers cannot be used.

Answered By – Benjamin T

Answer Checked By – Timothy Miller (BugsFixing Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *