By SirYakalot


2012-03-05 14:18:28 8 Comments

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:

6 comments

@Grimm The Opiner 2012-03-05 14:23:00

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 );
}

@SirYakalot 2012-03-06 11:04:10

which provides a method to trigger the call? the delegate? how? function pointer?

@Grimm The Opiner 2012-03-06 11:15:47

The delegate class will offer a method like Execute() which trigger the function call on the object the delegate wraps.

@David Peterson 2014-09-10 15:19:33

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.

@J.N. 2012-03-05 14:40:26

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);
}

@Xeo 2012-03-05 14:46:26

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.

@Matthieu M. 2012-03-05 14:46:54

@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!

@J.N. 2012-03-05 14:51:30

@MatthieuM. : fair point. I was considering function pointers to be legacy, but that's probably only my personal taste.

@J.N. 2012-03-05 14:53:32

@Xeo : my idea of a delegate is rather empiric. Maybe I am mixig too much function object and delegate (blame my former C# experience).

@SirYakalot 2012-03-06 14:44:17

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.

@J.N. 2012-03-06 15:05:42

@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.

@SirYakalot 2012-03-06 16:01:55

I keep hearing this reference to 'state', what exactly do people mean by this?

@J.N. 2012-03-06 21:56:32

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.

@Makalele 2015-02-15 18:54:28

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.

@kayleeFrye_onDeck 2016-01-28 03:40:25

@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.

@underscore_d 2016-07-24 14:55:09

The question was 'what are they', not 'list a bunch of ways to implement them'.

@J.N. 2016-07-25 03:29:37

They don't exist in C++ per se. Hence the list.

@Grimm The Opiner 2016-09-23 07:31:57

@Makalele "for class member function you can only pass static function". Not true. See my answer. stackoverflow.com/a/9568226/1158692

@Joe 2016-03-03 18:20:34

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);
    ...

@nmserve 2014-09-25 16:03:12

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.

@BitTickler 2013-03-29 16:50:24

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.

@Jason Nelson 2016-01-26 04:25:13

thank you for saying that

@kert 2016-08-25 16:11:38

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.

@prasad 2017-10-23 18:28:35

I am using std::function without heap in embedded system and it still works.

@SirYakalot 2012-03-23 14:32:42

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:

Related Questions

Sponsored Content

21 Answered Questions

[SOLVED] What is the "-->" operator in C++?

35 Answered Questions

13 Answered Questions

[SOLVED] What is the effect of extern "C" in C++?

31 Answered Questions

1 Answered Questions

[SOLVED] The Definitive C++ Book Guide and List

  • 2008-12-23 05:23:56
  • grepsedawk
  • 2110528 View
  • 4249 Score
  • 1 Answer
  • Tags:   c++ c++-faq

8 Answered Questions

[SOLVED] What is The Rule of Three?

11 Answered Questions

[SOLVED] What does the explicit keyword mean?

7 Answered Questions

5 Answered Questions

[SOLVED] What is the copy-and-swap idiom?

Sponsored Content