Qt/Qml and method overloads

2019-03-25 16:06发布

Just came across a weird behavior of Qt framework while invoking overloaded C++ methods from within Qml and trying to understand the reason behind it. Let's say I have a QList<QVariant>-like class with the following methods:

...
Q_SLOT void append(const QVariant &item);
Q_SLOT void append(const QVariantList &items);
Q_SLOT void insert(int index, const QVariant &item);
Q_SLOT void insert(int index, const QVariantList &items);
...

Qml:

onclicked: {
  var itemCount = myListObject.size();
  myListObject.insert(itemCount, "Item " + (itemCount + 1));
}

Qt somehow decides to invoke the void insert(int index, const QVariantList &items) overload with items argument set to a null QVariant an empty QVariantList instead of the void insert(int index, const QVariant &item) overload with QString wrapped in QVariant.

Now if I change the order of declarations as follows, it works as expected:

Q_SLOT void insert(int index, const QVariantList &items);
Q_SLOT void insert(int index, const QVariant &item);

I could not find anything under Qt framework's documentation regarding the order of declarations and how it affects the way methods are resolved during invoke.

Can someone please explain? Thank you.

标签: c++ qt qml moc
1条回答
聊天终结者
2楼-- · 2019-03-25 16:19

This question is related to overloading in JavaScript. Once you get to known with it -- you understand reason of "weird behavior" of your code. Just take a look at Function overloading in Javascript - Best practices.

In few words -- I recommend you to do next: since you can operate QVariant variables on both sides (QML and Qt/C++) -- pass variant as parameter, and process it on Qt/C++ side as you wish.

You can use something like this:

Your C++ class created and passed to QML (e.g. as setContextProperty("TestObject", &tc)):

public slots:
    Q_SLOT void insert(const int index, const QVariant &something) {
        qDebug() << __FUNCTION__;
        if (something.canConvert<QString>()) {
            insertOne(index, something.toString());
        } else if (something.canConvert<QStringList>()) {
            insertMany(index, something.toStringList());
        }
    }

private slots:
    void insertOne(int index, const QString &item) {
        qDebug() << __FUNCTION__ << index << item;
    }

    void insertMany(int index, const QStringList &items) {
        qDebug() << __FUNCTION__ << index << items;
    }

Somewhere in your QML:

Button {
    anchors.centerIn: parent
    text: "click me"
    onClicked: {
        // Next line will call insertOne
        TestObject.insert(1, "Only one string")
        // Next line will call insertMany
        TestObject.insert(2, ["Lots", "of", "strings"])
        // Next line will call insertOne
        TestObject.insert(3, "Item " + (3 + 1))
        // Next line will call insertOne with empty string
        TestObject.insert(4, "")
        // Next line will will warn about error on QML side:
        // Error: Insufficient arguments
        TestObject.insert(5)
    }
}
查看更多
登录 后发表回答