3

There is a small functor class I wrote which should be able to call class member functions by hiding a static wrapper function and a void pointer to the object. The example below does not compile due to an error when setting the wrapper function. What I want is a class member pointer as template argument. Does anyone know what is wrong there?

I think there could be another problem in the static function when calling the member function. I do not exactly know how to do this with template syntax. The minimal example compiles with C++11 enabled gcc.

#include <iostream>

template<class TReturn, class... TParameter>
struct Functor {

    TReturn (*ptr)(void*, TParameter...);
    void     *object;

    template<class TObject, class TMemberFunction>
    static TReturn memberCaller(void *obj, TParameter... params) {
        TObject *c = static_cast<TObject*>(obj);
        return (c->*(TObject::TMemberFunction))(params...);
    }

    TReturn operator()(TParameter... params) {
        return ptr(object, params...);
    }
};

class Test {
public:
    void func(int a) {
        std::cout << a << std::endl;
    }
};

int main(int argc, const char **argv) {
    Functor<void, int> f;
    Test               t;

    f.object = &t;
    f.ptr    = &Functor<void, int>::memberCaller<Test, Test::func>;

    f(100);
}
Surt
  • 15,501
  • 3
  • 23
  • 39
Gustavo
  • 919
  • 11
  • 34
  • 1
    You need to pass a pointer to member function of `Test` class that you want to call into `Functor`. `TMemberFunction` is not a type name. Actually you can just look up how `std::function` or `fastdelegate` is implemented. – user7860670 Aug 20 '17 at 15:40
  • I forgot to mention that in this case there is no stl available because I use it in an embedded system. – Gustavo Aug 20 '17 at 15:45
  • Related: https://stackoverflow.com/questions/4298408/5-years-later-is-there-something-better-than-the-fastest-possible-c-delegate – Passer By Aug 20 '17 at 16:51
  • What does this have to do with embedded systems? – Lundin Aug 21 '17 at 12:52

2 Answers2

3

Will something like this work for you?

#include <iostream>

template<class TObject, class T, class... TParameter>
struct Functor {

    using TMemberFunction = T (TObject::*)(TParameter...);
    TMemberFunction ptr;
    TObject     *object;


    T operator()(TParameter... params) {
        return (object->*ptr)(params...);
    }
};

class Test {
public:
    void func(int a) {
        std::cout << a << std::endl;
    }
};

template<typename T>
class TD;

int main() 
{
    Functor<Test, void , int> f;
    Test               t;

    f.object = &t;
    f.ptr = &Test::func;

    f(100);
}
Artemy Vysotsky
  • 2,694
  • 11
  • 20
  • 1
    Dont write your answer like a question. And maybe add some explanations instead of just dumping code. – GhostCat Aug 20 '17 at 19:23
  • That works fine but then I can use the Functor for only one specific class. There may be situations where not the class type counts but the function prototype. – Gustavo Aug 20 '17 at 19:25
  • Member functions of different classes have different types. So I'm not really see how it could be that "class type not counts" – Artemy Vysotsky Aug 20 '17 at 19:31
2

Set aside a few other errors, your code doesn't work for TMemberFunction in:

template<class TObject, class TMemberFunction>
static TReturn memberCaller(void *obj, TParameter... params) {
    // ...
}

Cannot be used to catch a pointer to a member function. TMemberFunction must be a type and you are not using it like that.

You can define your class as it follows instead:

template<class>
struct Functor;

template<class TReturn, class... TParameter>
struct Functor<TReturn(TParameter...)> {
    TReturn (*ptr)(void*, TParameter...);
    void     *object;

    template<class TObject, TReturn(TObject::*TMemberFunction)(TParameter...)>
    static TReturn memberCaller(void *obj, TParameter... params) {
        TObject *c = static_cast<TObject*>(obj);
        return (c->*TMemberFunction)(params...);
    }

    TReturn operator()(TParameter... params) {
        return ptr(object, params...);
    }
};

And use it this way:

Functor<void(int)> f;
Test               t;

f.object = &t;
f.ptr    = &Functor<void(int)>::memberCaller<Test, &Test::func>;

f(100);

That is, you can use now the member function as a template parameter for memberCaller and let it erase the type and use it internally once called.

I also slightly changed the definition of Functor so as to use it as:

Functor<void(int)>

That is a bit more explicit than the following when you plan to use it with a function type:

Functor<void, int>

My two cents, at least.


See the example above up and running on wandbox.

skypjack
  • 49,335
  • 19
  • 95
  • 187