mardi 14 septembre 2021

How to correctly capture parameter pack in std function lambda c++ 11

I have been trying to capture some parameter pack parameters within std function lambda, in order to save functions in memory for future use.

However, in some cases, where any of the values from these captured parameters are modified after having been captured, the future use of this ones are not what was expected.

I would like to store in my std function an immutable copy of the parameter pack. I have been reading about std move and std forward in some examples but, I do not really understand them and I am not able to suit them in my code with c++ 11. Compiler is complaning when using std forward...

This code will be implemented as a library, so users could use it for savig some text for future printing. This way we cannot manage what parameters we recieve in the parameter pack. This example must be valid for strings, const char *, int, float, ...

Here it is an example code: Code link

template <typename... Args>
void doPrint(std::ostream& out, const Args &... args)
{
    using expander = int[];
    (void)expander{0, (void(out << args), 0)...};
}

template<typename... Args>
void printArgs(const Args & ... args)
{
    doPrint(std::cout, args...);
}

class PrintTest
{
private:

    std::vector<std::function<void()>> myFunctions;   

public:

    template<typename... Args>
    void saveText(const char * text, const Args & ... args)
    {
        std::function<void()> f = [this, text, args...]()
        {
            std::cout << text;
            printArgs(args ...);
            std::cout << std::endl;
        };

        this->myFunctions.push_back(f);
    }

    void printSavedTexts()
    {
        for(auto fun : this->myFunctions)
            fun();

        this->myFunctions.clear();
    }

};

int main()
{
    PrintTest test;

    {
        int four = 4;
        test.saveText(" Hello world ", 1, 2, 3, std::to_string(four).c_str());

        std::string a ="Just";
        const char * b = " be ";
        test.saveText(" Bye, Bye! ", a.c_str(), b, std::string("yourself!").c_str());
        a = "?";

        for(int i = 0; i <= 5; ++i)
        {
            std::string n = std::to_string(i);
            test.saveText("", n.c_str());
        }
    }

   test.printSavedTexts();
}

The output of this example is:

// Hello world 1234
// Bye, Bye! ? be yourself!
// 5
// 5
// 5
// 5
// 5
// 5

And it should be:

// Hello world 1234
// Bye, Bye! Just be yourself!
// 0
// 1
// 2
// 3
// 4
// 5

Is there a better way to save the text and the parameter pack received in memory for future use? Instead of using std function stored in vector.

Aucun commentaire:

Enregistrer un commentaire