178

What is the general idea of a delegate in C++? What are they, how are they used and what are they used for?

I'd like to first learn about them in a 'black box' way, but a bit of information on the guts of these things would be great too.

This is not C++ at its purest or cleanest, but I notice that the codebase where I work has them in abundance. I'm hoping to understand them enough, so I can just use them and not have to delve into the horrible nested template awfulness.

These two The Code Project articles explain what I mean but not particularly succinctly:

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dollarslice
  • 9,917
  • 22
  • 59
  • 87

6 Answers6

207

You have an incredible number of choices to achieve delegates in C++. Here are the ones that came to my mind.


Option 1 : functors:

A function object may be created by implementing operator()

struct Functor
{
     // Normal class/struct members

     int operator()(double d) // Arbitrary return types and parameter list
     {
          return (int) d + 1;
     }
};

// Use:
Functor f;
int i = f(3.14);

Option 2: lambda expressions (C++11 only)

// Syntax is roughly: [capture](parameter list) -> return type {block}
// Some shortcuts exist
auto func = [](int i) -> double { return 2*i/1.15; };
double d = func(1);

Option 3: function pointers

int f(double d) { ... }
typedef int (*MyFuncT) (double d);
MyFuncT fp = &f;
int a = fp(3.14);

Option 4: pointer to member functions (fastest solution)

See Fast C++ Delegate (on The Code Project).

struct DelegateList
{
     int f1(double d) { }
     int f2(double d) { }
};

typedef int (DelegateList::* DelegateType)(double d);

DelegateType d = &DelegateList::f1;
DelegateList list;
int a = (list.*d)(3.14);

Option 5: std::function

(or boost::function if your standard library doesn't support it). It is slower, but it is the most flexible.

#include <functional>
std::function<int(double)> f = [can be set to about anything in this answer]
// Usually more useful as a parameter to another functions

Option 6: binding (using std::bind)

Allows setting some parameters in advance, convenient to call a member function for instance.

struct MyClass
{
    int DoStuff(double d); // actually a DoStuff(MyClass* this, double d)
};

std::function<int(double d)> f = std::bind(&MyClass::DoStuff, this, std::placeholders::_1);
// auto f = std::bind(...); in C++11

Option 7: templates

Accept anything as long as it matches the argument list.

template <class FunctionT>
int DoSomething(FunctionT func)
{
    return func(3.14);
}
Raxvan
  • 6,257
  • 2
  • 25
  • 46
J.N.
  • 8,203
  • 3
  • 29
  • 39
  • 2
    Great list, +1. However, only two really count as delegates here - capturing lambdas and the object returned from `std::bind`, and both really do the same thing, except lambdas aren't polymorphic in the sense that they can accept different argument types. – Xeo Mar 05 '12 at 14:46
  • 1
    @J.N: Why do you recommend not to use function pointers but seem to be okay with using the member methods pointers ? They are just identical! – Matthieu M. Mar 05 '12 at 14:46
  • 1
    @MatthieuM. : fair point. I was considering function pointers to be legacy, but that's probably only my personal taste. – J.N. Mar 05 '12 at 14:51
  • 1
    @Xeo : my idea of a delegate is rather empiric. Maybe I am mixig too much function object and delegate (blame my former C# experience). – J.N. Mar 05 '12 at 14:53
  • could you also just explain briefly what you think a delegate is nad what it does at the beginning of your question? I'm trying to grasp what it is that they do that would make someone want to use them over simply function pointers or passing references around. Thank you. – Dollarslice Mar 06 '12 at 14:44
  • 2
    @SirYakalot Something that behaves like a function, but that may hold state at the same time and can be manipulated like any other variable. One use for instance is to take a function that takes two parameters and force the 1st parameter to have certain value creating a new function with a single parameter (`binding` in my list). You can't achieve this with function pointers. – J.N. Mar 06 '12 at 15:05
  • I keep hearing this reference to 'state', what exactly do people mean by this? – Dollarslice Mar 06 '12 at 16:01
  • 1
    That the function has internal variables that are preserved from call to call. i.e. `int f() { static int i = 0; return ++i }`. Each call to `f()` will give a different result despite the parameters being the same. – J.N. Mar 06 '12 at 21:56
  • Great job. This really helped me digging into c++ a little deeper :) I'm personally using std::function for now. One thing is for class member function you can only pass static function. – Makalele Feb 15 '15 at 18:54
  • @J.N. or anyone else, is there any kind of general performance generalizations when comparing the use of a lambda as delegate to an std::function delegate? You mention std::function being slower, but not really compared to what it's slower than. – kayleeFrye_onDeck Jan 28 '16 at 03:40
  • The question was 'what are they', not 'list a bunch of ways to implement them'. – underscore_d Jul 24 '16 at 14:55
  • 4
    They don't exist in C++ per se. Hence the list. – J.N. Jul 25 '16 at 03:29
  • @Makalele "for class member function you can only pass static function". Not true. See my answer. http://stackoverflow.com/a/9568226/1158692 – Grimm The Opiner Sep 23 '16 at 07:31
43

A delegate is a class that wraps a pointer or reference to an object instance, a member method of that object's class to be called on that object instance, and provides a method to trigger that call.

Here's an example:

template <class T>
class CCallback
{
public:
    typedef void (T::*fn)( int anArg );

    CCallback(T& trg, fn op)
        : m_rTarget(trg)
        , m_Operation(op)
    {
    }

    void Execute( int in )
    {
        (m_rTarget.*m_Operation)( in );
    }

private:

    CCallback();
    CCallback( const CCallback& );

    T& m_rTarget;
    fn m_Operation;

};

class A
{
public:
    virtual void Fn( int i )
    {
    }
};


int main( int /*argc*/, char * /*argv*/ )
{
    A a;
    CCallback<A> cbk( a, &A::Fn );
    cbk.Execute( 3 );
}
Grimm The Opiner
  • 1,778
  • 11
  • 29
  • which provides a method to trigger the call? the delegate? how? function pointer? – Dollarslice Mar 06 '12 at 11:04
  • The delegate class will offer a method like `Execute()` which trigger the function call on the object the delegate wraps. – Grimm The Opiner Mar 06 '12 at 11:15
  • 5
    Instead of Execute, I would highly recommend in your case overriding the call operator - void CCallback::operator()(int). The reason for this is in generic programming, callable objects are expected to be called like a function. o.Execute(5) would be incompatible, but o(5) would fit nicely as a callable template argument. This class could also be generalized, but I assume you kept it simple for brevity (which is a good thing). Other than that nitpick, this is a very useful class. – David Peterson Sep 10 '14 at 15:19
23

The need for C++ delegate implementations are a long lasting embarassment to the C++ community. Every C++ programmer would love to have them, so they eventually use them despite the facts that:

  1. std::function() uses heap operations (and is out of reach for serious embedded programming).

  2. All other implementations make concessions towards either portability or standard conformity to larger or lesser degrees (please verify by inspecting the various delegate implementations here and on codeproject). I have yet to see an implementation which does not use wild reinterpret_casts, Nested class "prototypes" which hopefully produce function pointers of the same size as the one passed in by the user, compiler tricks like first forward declare, then typedef then declare again, this time inheriting from another class or similar shady techniques. While it is a great accomplishment for the implementers who built that, it is still a sad testimoney on how C++ evolves.

  3. Only rarely is it pointed out, that now over 3 C++ standard revisions, delegates were not properly addressed. (Or the lack of language features which allow for straightforward delegate implementations.)

  4. With the way C++11 lambda functions are defined by the standard (each lambda has anonymous, different type), the situation has only improved in some use cases. But for the use case of using delegates in (DLL) library APIs, lambdas alone are still not usable. The common technique here, is to first pack the lambda into a std::function and then pass it across the API.

Wouter J
  • 41,455
  • 15
  • 107
  • 112
BitTickler
  • 10,905
  • 5
  • 32
  • 53
  • I've done a version of Elbert Mai's generic callbacks in C++11 based on other ideas seen elsewhere, and it does seem to clear most of the issues you cite in 2). The only remaining nagging issue for me is i'm stuck using a macro in the client code to create the delegates. There is probably a template magic way out of this which i haven't yet solved. – kert Aug 25 '16 at 16:11
  • 5
    I am using std::function without heap in embedded system and it still works. – prasad Oct 23 '17 at 18:28
  • 2
    `std::function` doesn't _always_ dynamically allocate – Lightness Races in Orbit Jul 13 '19 at 14:56
  • 9
    This answer is more of a rant than an actual answer – Lightness Races in Orbit Jul 13 '19 at 14:57
10

Very simply, a delegate provides functionality for how a function pointer SHOULD work. There are many limitations of function pointers in C++. A delegate uses some behind-the-scenes template nastyness to create a template-class function-pointer-type-thing that works in the way you might want it to.

ie - you can set them to point at a given function and you can pass them around and call them whenever and wherever you like.

There are some very good examples here:

Olaf Dietsche
  • 72,253
  • 8
  • 102
  • 198
Dollarslice
  • 9,917
  • 22
  • 59
  • 87
5

An option for delegates in C++ that is not otherwise mentioned here is to do it C style using a function ptr and a context argument. This is probably the same pattern that many asking this question are trying to avoid. But, the pattern is portable, efficient, and is usable in embedded and kernel code.

class SomeClass
{
    in someMember;
    int SomeFunc( int);

    static void EventFunc( void* this__, int a, int b, int c)
    {
        SomeClass* this_ = static_cast< SomeClass*>( this__);

        this_->SomeFunc( a );
        this_->someMember = b + c;
    }
};

void ScheduleEvent( void (*delegateFunc)( void*, int, int, int), void* delegateContext);

    ...
    SomeClass* someObject = new SomeObject();
    ...
    ScheduleEvent( SomeClass::EventFunc, someObject);
    ...
Joe
  • 881
  • 7
  • 7
1

Windows Runtime equivalent of a function object in standard C++. One can use the whole function as a parameter (actually that is a function pointer). It is mostly used in conjunction with events. The delegate represents a contract that event handlers much fulfill. It facilitate how a function pointer can work for.

nmserve
  • 11
  • 5