Question

Here I have written a thread wrapper for c thread function pthread_create(). It will allow calling any method on any object and passing any number of arguments to that method. The API is:

template <typename T, typename R, typename... ATs>
pthread_t NewThread(T *obj, R (T::*mem)(ATs...), ATs... args);

Below is the template:

template<unsigned int i>  
class TupleUnpack 
{
    public:
    template<typename R, typename ...ATs, typename ...T_function_arguments>
    inline static R unpack (R  (*function) (ATs...), 
    std::tuple<ATs...> arguments_tuple,
    T_function_arguments  ...function_arguments)
    {
        return TupleUnpack<i-1>::unpack (function, arguments_tuple, std::get<i-1> (arguments_tuple), function_arguments...);
    }                       
};

template<> 
class TupleUnpack<0> 
{
    public:
    template<typename R, typename ...ATs, typename ...T_function_arguments>
    inline static R unpack (R                (*function) (ATs...), 
    std::tuple<ATs...> arguments_tuple,
    T_function_arguments              ...function_arguments)
    {
        return function (function_arguments...);
    }          
};
class CallCaller
{   
    virtual bool dispatch (void)=0;
};

template<typename T,typename R,typename ...ATs> 
class Call : public CallCaller
{
    public:     
    Call (T *obj,R (*function) (ATs...),ATs... arguments) :obj(obj),function (function),tuplearg (arguments...) {}

    ~Call() {}
    bool dispatch (void)
    {
        return TupleUnpack<sizeof ...(ATs)>::unpack (this->function, this->tuplearg);
    }

    private:
    std::tuple<ATs...> tuplearg;
    R (*function) (ATs...);

    T *obj;
};

void *test(int d,double sf)
{
    std::cout<<"yay my thread runs d="<<d<<" sf="<<sf<<std::endl;       
}

template<typename T,typename R,typename ...ATs> 
void* stub (void* vp)
{

    Call<T,R,ATs...>* call = static_cast<Call<T,R,ATs...>*>(vp);
    call->dispatch();       
    delete call;        
    pthread_exit (0);

}
template <typename T, typename R, typename... ATs>
pthread_t NewThread(T *ob, R (T::*mem)(ATs...), ATs... args)
{
    pthread_t tid;
    R (*func) (ATs...);
    Call<T,R,ATs...> *task=new Call<T,R,ATs...>(ob,&test,args...);

    pthread_create(&tid, nullptr, stub<T,R,ATs...>, task) ;

    return tid;
}

Below is the CPP file:

#include <tr1/tuple>
#include <utility>
#include <iostream>
#include <pthread.h>
#include <tuple>
#include <type_traits>
#include <utility>
#include "NewThread.hpp"

class X
{
    public:
    void *method(int a, double x)
    {
        std::cout<<"yay my tread runs a="<<a<<" x="<<x<<std::endl;
    }

};

int main()
{
    X x;
    int i;
    pthread_t tid = NewThread(&x, &X::method, 1234, 3.14);



    pthread_join(tid,NULL);

    std::cout<<"Thread Ended "<<tid<<std::endl;
    return 0;
}

I am trying to call the x::method() with the arguments. As you can see I have a test() function which is similar to x::method() just to demonstrate that my thread is working. But I want to be able to call the x::method(). Could anyone please guide me?

In Essence my current output is:

yay my thread runs d=1234 sf=3.14
Thread Ended 139766222432000

I want my output to be

yay my thread runs a=1234 x=3.14
Thread Ended 139766222432000
Was it helpful?

Solution

So this

R (*function) (ATs...);

is a function pointer, but you need a member function pointer

R (T::*function) (ATs...);

For calling a member function pointer you need an object and you have to call it with the following syntax:

self->*function(function_arguments...);

Note ->* syntax here.

So I added a T* self parameter to TupleUnpack<>::unpack and called it in Call<>::dispatch with the obj member. Now, I could replace the test function with the mem parameter in NewThread.

Here is a patch:

diff --git a/NewThread.hpp b/NewThread.hpp
index e121294..768f7d9 100644
--- a/NewThread.hpp
+++ b/NewThread.hpp
@@ -5,12 +5,12 @@ template<unsigned int i>
 class TupleUnpack 
 {
     public:
-    template<typename R, typename ...ATs, typename ...T_function_arguments>
-    inline static R unpack (R  (*function) (ATs...), 
+    template<typename T, typename R, typename ...ATs, typename ...T_function_arguments>
+    inline static R unpack (T* self, R (T::*function) (ATs...), 
     std::tuple<ATs...> arguments_tuple,
     T_function_arguments  ...function_arguments)
     {
-        return TupleUnpack<i-1>::unpack (function, arguments_tuple, std::get<i-1> (arguments_tuple), function_arguments...);
+        return TupleUnpack<i-1>::unpack (self, function, arguments_tuple, std::get<i-1> (arguments_tuple), function_arguments...);
     }                       
 };

@@ -18,12 +18,12 @@ template<>
 class TupleUnpack<0> 
 {
     public:
-    template<typename R, typename ...ATs, typename ...T_function_arguments>
-    inline static R unpack (R                (*function) (ATs...), 
+    template<typename T, typename R, typename ...ATs, typename ...T_function_arguments>
+    inline static R unpack (T* self, R (T::*function) (ATs...), 
     std::tuple<ATs...> arguments_tuple,
     T_function_arguments              ...function_arguments)
     {
-        return function (function_arguments...);
+        return (self->*function) (function_arguments...);
     }          
 };
 class CallCaller
@@ -35,19 +35,17 @@ template<typename T,typename R,typename ...ATs>
 class Call : public CallCaller
 {
     public:     
-    Call (T *obj,R (*function) (ATs...),ATs... arguments) :obj(obj),function (function),tuplearg (arguments...) {}
+    Call (T *obj,R (T::*function) (ATs...),ATs... arguments) :obj(obj),function (function),tuplearg (arguments...) {}

     ~Call() {}
     bool dispatch (void)
     {
-        return TupleUnpack<sizeof ...(ATs)>::unpack (this->function, this->tuplearg);
+        return TupleUnpack<sizeof ...(ATs)>::unpack(obj, this->function, this->tuplearg);
     }

     private:
     std::tuple<ATs...> tuplearg;
-    R (*function) (ATs...);
+    R (T::*function) (ATs...);

     T *obj;
 };
@@ -71,8 +69,7 @@ template <typename T, typename R, typename... ATs>
 pthread_t NewThread(T *ob, R (T::*mem)(ATs...), ATs... args)
 {
     pthread_t tid;
-    R (*func) (ATs...);
-    Call<T,R,ATs...> *task=new Call<T,R,ATs...>(ob,&test,args...);
+    Call<T,R,ATs...> *task=new Call<T,R,ATs...>(ob,mem,args...);

     pthread_create(&tid, nullptr, stub<T,R,ATs...>, task) ;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top