Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Qt Lambda reference



  • I have a Lambda slot:

    cnSignal = QObject::connect(this
                               ,&clsQtTextEdit::jsonTextChanged
                               ,[pobjScriptEng, strCall, strFile, strScript, strSID](QJsonObject objJSON) {
                                   objJSON.insert(clsXMLnode::mscszAttrSubscriberID, strSID);
                                   QString strJSON = clsXMLnode::strJSON(objJSON)
                                          ,strScriptWithCall = static_cast<QString>(strScript)
                                                                            + static_cast<QString>(strCall)
                                                                            + static_cast<QString>("(" + strJSON + ");");
                                   pobjScriptEng->evaluate(strScriptWithCall);
                               });
    

    I have multiple connections to different signals that all share the same Lambda function, is there any way to defined a local single instance of this and assign a reference or pointer to that instance instead of replication the same logic in multiple places?

    I'm thinking like a function pointer.



  • @SPlatten

    1. If you only want use that lambda in the current scope. I think auto is the best because it is very simple.
    auto func = [pobjScriptEng, strCall, strFile, strScript, strSID](QJsonObject objJSON) {
                                   objJSON.insert(clsXMLnode::mscszAttrSubscriberID, strSID);
                                   QString strJSON = clsXMLnode::strJSON(objJSON)
                                          ,strScriptWithCall = static_cast<QString>(strScript)
                                                                            + static_cast<QString>(strCall)
                                                                            + static_cast<QString>("(" + strJSON + ");");
                                   pobjScriptEng->evaluate(strScriptWithCall);
                               };
    cnSignal = QObject::connect(this , &clsQtTextEdit::jsonTextChanged , func);
    
    1. But if you need to assign the lambda to a class member, then you need std::function because you cannot define an auto member variable.
    std::function<void(QJsonObject)> func = [pobjScriptEng, strCall, strFile, strScript, strSID](QJsonObject objJSON) {
                                   objJSON.insert(clsXMLnode::mscszAttrSubscriberID, strSID);
                                   QString strJSON = clsXMLnode::strJSON(objJSON)
                                          ,strScriptWithCall = static_cast<QString>(strScript)
                                                                            + static_cast<QString>(strCall)
                                                                            + static_cast<QString>("(" + strJSON + ");");
                                   pobjScriptEng->evaluate(strScriptWithCall);
                               };
    cnSignal = QObject::connect(this , &clsQtTextEdit::jsonTextChanged , func);
    


  • @SPlatten
    I believe you are asking to be able to create & re-use a lambda "variable", right? I looked into this a couple of weeks ago. From what I read, C++ lambda object-variables are not so bad to write if they do not take any parameters. But if they do --- your QJsonObject objJSON --- then it's not so easy. If you persist with that, I read you must go via std::function() to do the job. An alternative suggestion was to move any parameters to the [...] context instead of passing as a function parameter.

    I gave up on it as being too much hassle. But I shall watch this question to see whether one of our resident C++ experts wants to show just how easily it can be done....



  • I think this is a C++11 question rather than a Qt one.
    The key points here are auto and std::function.
    You can refer to this example from https://en.cppreference.com/w/cpp/language/lambda :

    #include <vector>
    #include <iostream>
    #include <algorithm>
    #include <functional>
     
    int main()
    {
        std::vector<int> c = {1, 2, 3, 4, 5, 6, 7};
        int x = 5;
        c.erase(std::remove_if(c.begin(), c.end(), [x](int n) { return n < x; }), c.end());
     
        std::cout << "c: ";
        std::for_each(c.begin(), c.end(), [](int i){ std::cout << i << ' '; });
        std::cout << '\n';
     
        // the type of a closure cannot be named, but can be inferred with auto
        // since C++14, lambda could own default arguments
        auto func1 = [](int i = 6) { return i + 4; };
        std::cout << "func1: " << func1() << '\n';
     
        // like all callable objects, closures can be captured in std::function
        // (this may incur unnecessary overhead)
        std::function<int(int)> func2 = [](int i) { return i + 4; };
        std::cout << "func2: " << func2(6) << '\n';
    }
    


  • @Bonnie , thank you, do you have an example on how to apply that technique to my example slot?



  • @SPlatten

    1. If you only want use that lambda in the current scope. I think auto is the best because it is very simple.
    auto func = [pobjScriptEng, strCall, strFile, strScript, strSID](QJsonObject objJSON) {
                                   objJSON.insert(clsXMLnode::mscszAttrSubscriberID, strSID);
                                   QString strJSON = clsXMLnode::strJSON(objJSON)
                                          ,strScriptWithCall = static_cast<QString>(strScript)
                                                                            + static_cast<QString>(strCall)
                                                                            + static_cast<QString>("(" + strJSON + ");");
                                   pobjScriptEng->evaluate(strScriptWithCall);
                               };
    cnSignal = QObject::connect(this , &clsQtTextEdit::jsonTextChanged , func);
    
    1. But if you need to assign the lambda to a class member, then you need std::function because you cannot define an auto member variable.
    std::function<void(QJsonObject)> func = [pobjScriptEng, strCall, strFile, strScript, strSID](QJsonObject objJSON) {
                                   objJSON.insert(clsXMLnode::mscszAttrSubscriberID, strSID);
                                   QString strJSON = clsXMLnode::strJSON(objJSON)
                                          ,strScriptWithCall = static_cast<QString>(strScript)
                                                                            + static_cast<QString>(strCall)
                                                                            + static_cast<QString>("(" + strJSON + ");");
                                   pobjScriptEng->evaluate(strScriptWithCall);
                               };
    cnSignal = QObject::connect(this , &clsQtTextEdit::jsonTextChanged , func);
    


  • @Bonnie said in Qt Lambda reference:

    auto func = [pobjScriptEng, strCall, strFile, strScript, strSID](QJsonObject objJSON) {
    objJSON.insert(clsXMLnode::mscszAttrSubscriberID, strSID);
    QString strJSON = clsXMLnode::strJSON(objJSON)
    ,strScriptWithCall = static_cast<QString>(strScript)
    + static_cast<QString>(strCall)
    + static_cast<QString>("(" + strJSON + ");");
    pobjScriptEng->evaluate(strScriptWithCall);
    };

    Perfect, thank you!



  • @Bonnie
    If I can chip in, now that OP seems happy.

    So, you managed to do it even with parameters without having to use std::function(). I thought I read that was needed when I looked at SO posts, but perhaps that was older version of C++.

    Armed with your answer, I just went back over code and did my lambda-to-be-used-many-times-in-one-function with your auto func1 = [](...) { return ...; }; and it wasn't so hard after all! So thanks very much for example.


Log in to reply