2

I came across the following blog post which explains how to build C++ delegates using variadic templates: http://blog.coldflake.com/posts/2014-01-12-C++-delegates-on-steroids.html

I'm reproducing the Delegate class in the post here:

template<typename return_type, typename... params>
class Delegate
{
    typedef return_type (*Type)(void* callee, params...);
public:
    Delegate(void* callee, Type function)
         : fpCallee(callee)
         , fpCallbackFunction(function) {}

template <class T, return_type (T::*TMethod)(params...)>
static Delegate from_function(T* callee)
{
    Delegate d(callee, &methodCaller<T, TMethod>);
    return d;
}

return_type operator()(params... xs) const
{
    return (*fpCallbackFunction)(fpCallee, xs...);
}

private:

    void* fpCallee;
    Type fpCallbackFunction;

    template <class T, return_type (T::*TMethod)(params...)>
    static return_type methodCaller(void* callee, params... xs)
    {
        T* p = static_cast<T*>(callee);
        return (p->*TMethod)(xs...);
    }
};

And an example of how to use the class is given here:

class A
{
public:
    int foo(int x)
    {
        return x*x;
    }
    int bar(int x, int y, char a)
    {
        return x*y;
    }
};
int main()
{
    A a;
    auto d = Delegate<int, int>::from_function<A, &A::foo>(&a);
    auto d2 = Delegate<int, int, int, char>::from_function<A, &A::bar>(&a);
    printf("delegate with return value: d(42)=%d\n", d(42));
    printf("for d2: d2(42, 2, 'a')=%d\n", d2(42, 2, 'a'));
    return 0;
}

The technique is pretty cool, except that I would also like to have the Delegate class manage the callee's lifetime (in other words I would like to instantiate A on the heap and when the Delegate instance is deleted or goes out of scope, it should also be able to delete the callee (the A instance in this case)). Is there a simple way of doing this? Am I missing something? One solution would be to also pass a deleter object, which would cast the void* fpCallee to the correct type and then call delete ont it. Is there a better solution for this?

BigONotation
  • 4,406
  • 5
  • 43
  • 72

1 Answers1

4

You could use shared_ptr<void> to store the callee instead of void* (see this question for why this doesn't cause delete problems; thanks Kindread). This would require you to keep every callee in a shared_ptr, but if you don't mind that, it would solve your problem.

And while this isn't an answer to the question, you could accomplish pretty much the same thing using a lambda instead of Delegate:

auto a = std::make_shared<A>();
auto d = [a](int x) { a->foo(x); };
Community
  • 1
  • 1
dlf
  • 9,045
  • 4
  • 32
  • 58