0

I am writing a library for thread management using C++ for my app and as part of the same I am trying to write a template class that takes a FunctionPointer to be executed inside the run function. I am a Java developer and trying to visualize as follows:

class MyRunnable : public Runnable {

    public:
        MyRunnable(fp)
        {
            mFp = fp;
        }

    private:

    FunctionPointer mFp;

    // Will be called by the thread pool using a thread
    void run() 
    {
         mFp();
    }

}

class ThreadManager {

    public:
        void execute(MyRunnable runnable) {
            executeOnAThreadPool(runnable);
        }

}

Since I am not fluent with C++ syntax, I am finding hard to get the constructor defined to take a FunctionPointer as argument with variable number of arguments for the FunctionPointer. Something like:

MyRunnable(Fp fp, Args... args)

Can someone please help me defining the constructor for MyRunnable class above. Thanks.

max66
  • 65,235
  • 10
  • 71
  • 111
Androider
  • 23
  • 4
  • I suggest you first try existing C++ libraries, and also learn about lambdas, Invokables, `std::thread`'s etc. – einpoklum Feb 06 '21 at 18:57
  • The parameters can be passed when you call `mFp();`. You need to provide these either as parameters of `run()` as well, or at the constructor, to be stored as class member variables for later use. – πάντα ῥεῖ Feb 06 '21 at 18:57
  • You could dispense with your `Runnable` interface. `std::function` is pretty versatile, and could cover your needs well. – StoryTeller - Unslander Monica Feb 06 '21 at 19:00
  • @πάνταῥεῖ Yes, I am looking for a template to have arguments passed to the constructor and saved as member variables. How do I achieve it ? – Androider Feb 06 '21 at 19:03
  • @StoryTeller-UnslanderMonica Please tell me how std::function can be used to solve my problem. – Androider Feb 06 '21 at 19:04
  • @Androider If you have variadic parameters (`...`), you might store them through a `std::tuple`. But in that case, it's easier to have these at the `run()` function, and use _perfect forwarding_. – πάντα ῥεῖ Feb 06 '21 at 19:04
  • Your thread manager can accept `std::function`. If calling code wants to bind arguments, it uses a lambda expression. And that's pretty much it. – StoryTeller - Unslander Monica Feb 06 '21 at 19:06
  • @StoryTeller-UnslanderMonica As I admitted in my question, I am learning C++ and finding it difficult to get the ideas converted to syntax. Can you please provide a pseudo code. – Androider Feb 06 '21 at 19:08
  • Side note: oftentimes overloading `operator()` in function objects is considered more idiomatic C++ than providing some sort of `run` method. It's by no means necessary, yet `run` method seems a "javaism" that might become an issue when shipping the library to external parties. – alagner Feb 06 '21 at 19:33
  • @alagner Interesting point! – Androider Feb 06 '21 at 19:38

1 Answers1

3

Not sure... but seems to me that you're looking something as

class MyRunnable
 {
   private:
      std::function<void()> mF;

   public:       
      template <typename F, typename ... Args>
      MyRunnable (F && f, Args && ... args)
       : mF{ [&f, &args...](){ std::forward<F>(f)(std::forward<Args>(args)...); } }
       { }

      void run ()
       { mF(); }
 };

The following is a full compiling example

#include <iostream>
#include <functional>

class MyRunnable
 {
   private:
      std::function<void()> mF;

   public:       
      template <typename F, typename ... Args>
      MyRunnable (F && f, Args && ... args)
       : mF{ [&f, &args...](){ std::forward<F>(f)(std::forward<Args>(args)...); } }
       { }

      void run ()
       { mF(); }
 };

void foo (int a, long b, std::string const & c)
 { std::cout << "executing foo() with " << a << ", " << b << ", " << c << '\n'; }

int main ()
 {
   MyRunnable  mr{foo, 1, 2l, "three"};

   std::cout << "before run" << '\n';

   mr.run();

 }

that prints

before run
executing foo() with 1, 2, three
max66
  • 65,235
  • 10
  • 71
  • 111
  • Thanks a lot. C++ is just awesome. If I have a member function of class Foo, something like Foo::a, how do I pass it to MyRunnable ? Using MyRunnable mr{&Foo::A}; throws compilation error as 'Cannot create a non-constant pointer to member function' – Androider Feb 06 '21 at 19:35
  • @Androider member function (when called directly) takes an implicit first argument: pointer to the object. Have a look here: https://stackoverflow.com/a/17131787/4885321 EDIT: or check out `mem_fn` if you'd like to like to pass the object to it as an argument. – alagner Feb 06 '21 at 19:56
  • @Androider - "how do I pass it to MyRunnable ? " - Do you want to pass also an object of type `Foo`? – max66 Feb 06 '21 at 20:19
  • @max66 I was asking for something like: class Foo { void print(int x) { // print something } void doSomething() { MyRunnable run {&Foo::print, x}; Bar::threadPoolRun(run); } } – Androider Feb 07 '21 at 03:28
  • @Androider - If you want to exec `Foo::print()` you need (if `print()` isn't `static`) a `Foo` object. Who supply the `Foo` object? – max66 Feb 07 '21 at 14:59
  • Thanks @max66.. I was able to read through cpp reference and use lambda in association with above template to achieve the function call successfully. – Androider Feb 07 '21 at 18:27