2

I've been working on making a small delegate template exercise to 1.) better myself, 2.) better understand template metaprogramming, and to 3.) possibly even use delegates for some event-driven programming (as I do not have access to standard libraries). According to this answer, something like the following can be implemented for functions:

template <typename T, typename R, typename ...Args>
R proxycall(T & obj, R (T::*mf)(Args...), Args &&... args)
{
    return (obj.*mf)(args...);
}

proxycall(myobj, &MyObj::func);

It seems as if the compiler can figure out the return type, class type, and parameter types just by passing myobj and &MyObj::func into the template. Can the same method as above be used to create a delegate class (class that stores both a reference to an object and a pointer-to-member function)?

Delegate d(myobj, &MyObj::func); /* Preferred */

or

Delegate<myobj, &MyObj::func> d; /* Ok */

The following class is my Delegate class and it has the unfortunate side-effect of having to specify the ReturnType and the types of the Parameters in the corresponding member function. As I see above, the compiler can figure that stuff out. So, how can I have the compiler help me out?

template <class Class, typename ReturnType, typename ... Parameters>
class Delegate {
    public:
        typedef ReturnType (Class::*Method)(Parameters ... params);

        Delegate(Class& ref, Method m) : obj(ref), method(m) {}
        ReturnType operator()(Parameters ... params) { return (obj.*method)(params...); }
        ReturnType Invoke(Parameters ... params) { return operator()(params...); }
    private:
        Class& obj;
        Method method;
};

/* Usage */
Delegate<MyObj, void> d(myobj, &MyObj::func);
         ^^^^^^^^^^^
             ick
Community
  • 1
  • 1
thndrwrks
  • 1,644
  • 1
  • 17
  • 29
  • If I'm not mistaken, in `proxycall` you should have `std::forward(args)...` instead of `args...`. – cdhowie Nov 05 '14 at 18:13

1 Answers1

2
Delegate d(myobj, &MyObj::func);

Basically this would make Delegate independent from the type of the member function and its class. Only the constructor template will know about the return type and the parameter types. The class does not. You will need type erasure to make the type of the delegate independent of the type of the internal function object - basically you would implement an std::function whose implementation is explained here (note that function is not fixed in terms of the return or parameter types).

If all you want is nicer syntax and less redundancy in the code, use a factory template:

template <typename T, typename R, typename ...Args>
Delegate<T, R, Args...> make_delegate(T& obj, R (T::*mf)(Args...))
{
    return {obj, mf};
}

Which, when called with appropriate arguments, returns a Delegate with the corresponding type properly initialized.

auto deleg = make_delegate(myobj, &MyObj::func);
Community
  • 1
  • 1
Columbo
  • 60,038
  • 8
  • 155
  • 203
  • I don't think you want the `T` in `Delegate`. That goes against everything you said immediately before it :) – Barry Nov 05 '14 at 18:37
  • @Barry I do want the `T` in there, I simply provided a factory for *his* class. It was at the wrong position though, thanks for the hint. – Columbo Nov 05 '14 at 18:41
  • What about `Delegate d`; Is this even possible? Can I pass a reference to a class and a pointer-to-member function as template parameters? – thndrwrks Nov 05 '14 at 18:45
  • 1
    @thndrwrks No, this is not possible. Template non-type arguments must be constant expressions. `myobj` is surely not a constant expression. The address of the member function is, though. You could just pass the address of that member function and assign `myobj` through the constructor. – Columbo Nov 05 '14 at 18:50
  • Ok that answers one question. Now how do I go about writing the template to accept such a function pointer? (I get so confused with template syntax). – thndrwrks Nov 05 '14 at 19:01
  • That is, how do I get my template to recognize `Delegate<&MyObj::func>`? – thndrwrks Nov 05 '14 at 19:16
  • 1
    @thndrwrks That is impossible. The template cannot deduce the type of its template argument. It has to be known in some form to `Delegate`. – Columbo Nov 05 '14 at 19:19