Home > Mobile >  How to pass an argument to a member function wrapped in std::function<void()>?
How to pass an argument to a member function wrapped in std::function<void()>?

Time:10-01

At first it seemed clear that I shouldn't be able to do this, but then I discovered that it can be done with free functions.

Here is an example where I pass void() functions from Child to Parent. The parent calls the function when their Frame comes up.

I have figured out the syntax to pass free functions with arguments, but I can't figure out how to pass a member function of Child with an argument.

Please help.

#include <iostream>
#include <vector>
#include <map>
#include <functional>

void f_Free1()      { std::cout << "Hi there hello. I'm a free function without arguments."; }
void f_Free2(int i) { std::cout << "Hi there hello. I'm a free function with an argument. It's " << i; }

class Parent
{
    std::map<unsigned int, std::vector<std::function<void()>>> Tasks;

protected:

    void addTask(unsigned int frame, std::function<void()> task) { Tasks[frame].push_back(task); }

public:

    virtual ~Parent() {}
    unsigned int Frame = 0;

    void tick()
    {
        if (Tasks.count(Frame))
        {
            for (auto task : Tasks[Frame]) 
            { 
                task(); 
            }
        }

        Frame  ;
    }
};

class Child : public Parent
{
    void f_Child1()      { std::cout << "This is a private Child function without arguments. "; }
    void f_Child2(int i) { std::cout << "This is a private Child function with an argument. It's " << i; }

public:

    Child() 
    {
        addTask(3, f_Free1);
        addTask(5, [a = int(4)] () { f_Free2(a); } ); // THIS WORKS!!!

        addTask(7, std::function<void()> { std::bind(&Child::f_Child1, this) });
        addTask(9, std::function<void()> { std::bind([a = int(4)]() { &Child::f_Child2(a), this) } }); // CAN'T MAKE THIS WORK
    }
};

int main()
{
    Child child;

    for (unsigned int i = 0; i < 12; i  )
    {
        std::cout << "[" << child.Frame << "]";
        child.tick(); // runs tasks whose frames are up
        std::cout << std::endl;
    }

    return 0;
}

CodePudding user response:

Ditch the bind.

Use [this]() { f_Child1(); } and [this]() { f_Child(4); }.

Also, the free version can be just []() { f_Free2(4); }.

CodePudding user response:

std::bind's syntax would be:

  • std::bind(&f_Free1)
  • std::bind(&f_Free2, 4)
  • std::bind(&Child::f_Child1, this)
  • std::bind(&Child::f_Child2, this, 4)

But lambda is simpler for most people:

  • &f_Free1 is fine, else [](){ return f_Free1(); }
  • [](){ return f_Free2(4); }
  • [this]() { return this->f_Child1(); )
  • [this]() { return this->f_Child2(4); )

return can be omitted here as functions return void.
this-> can be omitted in lambda.
you might capture more or differently for arguments.

  • Related