dimanche 25 mars 2018

Getting function handler to class method to make callback class

I would like to create a template callback class which can call either a static function or a class method, but I'm struggling hard.

I have the following class:

template<class R, class ... Args> class Callback;
template<class R, class ... Args> class Callback<R(Args...)> {
protected:
    typedef R (*func_t)(Args...);
    func_t f;
public:

    /**
     * Constructor from function
     * @param fIn Input function
     */
    Callback(const func_t &fIn) :
            f(fIn) {
    }

    virtual ~Callback() {
    }

    /**
     * Call operator
     * @param args Arguments for function call
     * @return Return of function
     */
    inline R operator()(Args ... args) const {
        return f(args...);
    }
};

When I create a callback object from a static function or a lambda it works perfectly:

int add(int x, int y, int z) {
    return x + y + z;
}

int main() {
    typedef Callback<int(int, int, int)> cb_t;
    cb_t addCb(add);
    std::cout << addCb(2, 3, 4) << std::endl;
    cb_t mulCb([](int x, int y, int z){return x * y * z;});
    std::cout << mulCb(2, 3, 4) << std::endl;
    return 0;
}

which displays:

9
24

Now I want to make it available to class methods using std::bind. I tried adding a constructor in Callback class:

template<typename T> Callback(T &&obj, R (T::*fIn)(Args...)) : f(std::bind(fIn,obj)){
}

And new main:

class foo {
public:
    foo() : x(12) {};

    int myFunc(int a, int b, int c) {
        this->x = (2 + a) * (b + c);
        return this->x;
    }

    int getX() {
        return x;
    }

protected:
    int x;
};

int main() {
    typedef Callback<int(int, int, int)> cb_t;
    foo fooInstance;
    cb_t fooMethodCb(&fooInstance, &foo::myFunc);
    std::cout << fooMethodCb(2, 3, 4) << std::endl;
    return 0;
}

which doesn't compile. I get an error with constructor:

./src/callback.h: note: candidate template ignored: deduced conflicting types for parameter 'T' ('foo *' vs. 'foo')

which seems normal, but I just can't find the good usage of T in my constructor to get it working.

Thanks for your help!

Note: I need it to be c++11-compatible.

Aucun commentaire:

Enregistrer un commentaire