Home > Software engineering >  How can I store a std::bind function pointer?
How can I store a std::bind function pointer?

Time:06-11

Here is the code I am using

#include <functional>
#include <iostream>
#include <thread>

class Context {
private:
  std::thread thread;
  bool running;
  void run() {
    while (running) {
      if (function != nullptr) {
        function();
        function = nullptr;
      }
    }
  }
  void (*function)();

public:
  Context() : running(true) { thread = std::thread(&Context::run, this); }
  ~Context() {
    running = false;
    thread.join();
  }

  template <typename T, typename... Args> void call(T function, Args... args) {
    this->function = std::bind(function, args...);
  }
};

// Here are some test functions
void f1() { std::cout << "f1" << std::endl; }

void f2(int a) { std::cout << "f2(" << a << ")" << std::endl; }

void f3(int a, int b) {
  std::cout << "f3(" << a << ", " << b << ")" << std::endl;
}

int main() {
  Context context;
  context.call(f1);
  context.call(f2, 1);
  context.call(f3, 1, 2);
  return 0;
}

I want this class to create a thread that will run some functions. The thread will be created when the class is created and will be stopped when the class is destroyed. In order to run a function, you can call the Context::call function with the function to be called and the arguments.

f2(2);

becomes

context.call(f2, 2);

and

f3(3, 4);

becomes

context.call(f3, 3, 4);

However I am getting errors when I try to compile this file :

t.cpp: In instantiation of 'void Context::call(T, Args ...) [with T = void (*)(); Args = {}]':
t.cpp:55:15:   required from here
t.cpp:42:31: error: cannot convert 'std::_Bind_helper<false, void (*&)()>::type' to 'void (*)()' in assignment
   42 |     this->function = std::bind(function, args...);
      |                      ~~~~~~~~~^~~~~~~~~~~~~~~~~~~
      |                               |
      |                               std::_Bind_helper<false, void (*&)()>::type
t.cpp: In instantiation of 'void Context::call(T, Args ...) [with T = void (*)(int); Args = {int}]':
t.cpp:56:15:   required from here
t.cpp:42:20: error: cannot convert 'std::_Bind_helper<false, void (*&)(int), int&>::type' to 'void (*)()' in assignment
   42 |     this->function = std::bind(function, args...);
      |     ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
t.cpp: In instantiation of 'void Context::call(T, Args ...) [with T = void (*)(int, int); Args = {int, int}]':
t.cpp:57:15:   required from here
t.cpp:42:20: error: cannot convert 'std::_Bind_helper<false, void (*&)(int, int), int&, int&>::type' to 'void (*)()' in assignment

I know this code is unsafe and has flaws but I used mutexes and security measures in the real implementation. This example is just the minimal to reproduce the error.

CodePudding user response:

You can make use of std::function. In particular, replace void (*function)() with std::function<void ()> function as shown below:

class Context {
private:
  //other code here
  
  std::function<void ()> function;

};

Working demo

CodePudding user response:

I would choose some other approach. Take a look:

#include <functional>
#include <iostream>
#include <thread>
using namespace std;

class Context
{
    thread t;

public:
    template<class Func, class... Args>
    Context(Func func, const Args&... args) : t{ func, cref(args)... } {

    }
    ~Context() {
        if (t.joinable())
            t.join();
    }
};

void f1() {
    cout << "f1" << endl;
}

void f2(int) {
    cout << "f2" << endl;
}

void f3(int, int) {
    cout << "f3" << endl;
}

int main()
{
    Context c1{ f1 };
    Context c2{ f2, 1 };
    Context c3{ f3, 1, 2 };
}
  • Related