0

I'm trying to create sort of a closure callback class and run into some problems with template parameter deduction and matching

(The class works as follows: Upon construction, it will take a member or non-member function as well as a variable (CAPARGS) number of arguments into a closure. The closure can then be called with a variable number of arguments (CALLARGS), and it will call its callback function with CAPARGS and CALLARGS.)

  • I get compile errors when invoking its constructors (See below under "Test code", two errors are marked).
  • Compile errors arise in both cases because it can not find a matching constructor.
  • I marked the constructors which SHOULD be taken at each error under "Class code", and I give the error (reason for not matching) given for THAT constructor right below here.

ERROR 1:

candidate template ignored: could not match 'function' against 'void (*)(int)'

ERROR 2:

note: candidate template ignored: failed template argument deduction

Class code:

template <class... CALLARGS>
class Closure{

    public:

        // Constructor intended for use at ERROR 1
        template <class OBJ, class... CAPARGS>
        Closure(OBJ* obj, void (OBJ::*fct)(CAPARGS..., CALLARGS...), CAPARGS... capArgs){
            callback =
                [=] (CALLARGS... callArgs) -> void{
                    (obj->*fct)(capArgs..., callArgs...);
                };
        }

        // Constructor intended for use at ERROR 1
        template <class... CAPARGS>
        Closure(std::function<void(CAPARGS..., CALLARGS...)>, CAPARGS... capArgs){
            callback =
                [=] (CALLARGS... callArgs) -> void{
                    fct(capArgs..., callArgs...);
                };
        }

        void operator () (CALLARGS... callArgs){
            callback(callArgs...);
        }

    private:
        std::function<void(CALLARGS...)> callback;

};

Test code:

class A{
    public:
        virtual void fct(int a){
            ...
        }
};


void plusF(int a){
    ...
}

int main(void) {

    A a;

    Closure<int> callF(plusF); // **ERROR 1 from here**
    Closure<int> callA(&a, &A::fct); // **ERROR 2 from here**

    callF(1);
    callA(2);

}

I'm aware that maybe I'm doing stuff which exceeds my skills. But can I somehow fix this?

(Btw, side question: Is it reasonable to call this class Closure, or does such a construct have a different name?)

Michael
  • 7,407
  • 8
  • 41
  • 84

1 Answers1

1

Some of your variadic template are non deductible (or create conflict), you may do instead:

template <class... CALLARGS>
class Closure{
public:

    template <class OBJ, typename M, class... CAPARGS>
    Closure(OBJ* obj, M (OBJ::*fct), CAPARGS... capArgs){
        callback =
            [=] (CALLARGS... callArgs) -> void{
                (obj->*fct)(capArgs..., callArgs...);
            };
    }

    template <typename F, class... CAPARGS>
    Closure(F fct, CAPARGS... capArgs){
        callback =
            [=] (CALLARGS... callArgs) -> void{
                fct(capArgs..., callArgs...);
            };
    }
    void operator () (CALLARGS... callArgs){
        callback(callArgs...);
    }
private:
    std::function<void(CALLARGS...)> callback;
};

Demo

std::bind may be a simpler alternative:

using namespace std::placeholders;
A a;

auto callF = std::bind(plusF, _1);
auto callA = std::bind(&A::fct, &a, _1);

callF(1);
callA(2);

Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • Thanks, that helps. But it's some kind of magic for me... Could you recommend a good starting point (link, search words, book) for learning more about this? – Michael Sep 10 '15 at 08:49
  • 2
    That PMF should really be reduced to a simple pointer to member (a `F O::*`); as it is it doesn't handle `const` member functions etc. Also, the class type of the PMF should be allowed to be different from `OBJ`, as otherwise it will break with inherited members. – T.C. Sep 10 '15 at 08:50