Home > Net >  How to store parameter packed function for later called
How to store parameter packed function for later called

Time:11-23

I'm building a project with a signal/slot library, and i'd like to be able to execute the slot in a different thread than the signal calling it, like Qt does.

To do that, I'm trying to store a function call with parameter pack to allow varying args number :

#include <functional>
#include <iostream>

struct SlotProxy {
    template<typename Func, typename ...Args>
    void PostEvent(Func func, Args ... args) {
        _callback = [func, &args...]() {
            func(args...);
        };
    }

    void operator()() {
        _callback();
    }

    std::function<void()> _callback;
};

struct Obj {
    int i{};
    void Print() {
        std::cout << this << " - Obj val : " << i << std::endl;
    }

    void Slot(Obj& obj) {
        obj.Print();
    }
};

void Test(Obj& obj) {
    obj.Print();
}

int main() {
    Obj obj{};
    obj.Print();

    SlotProxy sp{};
    
    // error : no matching call for bind
    auto bind = std::bind(&SlotProxy::PostEvent, &sp, &Test, std::placeholders::_1);

    bind(obj);
}

Here std::bind gives me an error that it can't find the matching definition, what am I doing wrong?

Subsidary question : How can I bind a member function as a parameter to PostEvent? Does a nested std::bind would work ?

std::bind(&SlotProxy::PostEvent, &p, std::bind(&Obj::Slot, obj, ???), std::placeholders::_1);

CodePudding user response:

The problem(error) is that PostEvent is a member function template and when it is used as an argument to std::bind as in &SlotProxy::PostEvent, the type of its template parameter(s) aren't known.

This means that we need to either use default arguments or explicitly tell the compiler the type of its template parameters. Below is a contrived example:

template <typename T>
class myclass {
public:
  template<typename U>
  void func(const U&)
  {

  }
};
int main(){

  myclass<int> obj;
  //--------------------------------------------vvvvvv----------->pass the argument explicitly
  auto mylambda = std::bind(&myclass<int>::func<double>, &obj, 5);
  mylambda();

}

Similarly, you will either need to explicitly pass the template arguments or use default arguments wherever possible.

You should also take care of additional problems that the code might have like dangling references etc.

  •  Tags:  
  • c
  • Related