when writing cocos2d-x based game we often need some kind of callback system. Cocos2d-x 2.x uses C-like callback with all those selectors and call_func preprocessor machinery. It was pretty hard for me to remember all those macros and also difficult to debug, because of bug-prone C casts, so I’ve decided to create both more powerful and user-friendly C++11 callbacks/delegates.

But it thing that the typical use will be just like this:@ pSomeObject.setCallback( Delegate( this, &SomeCalss::method ) ); //method takes a CCNode* and returns nothing (void)@

Delegates are designed to by passed by value/reference/move, because copying/swapping two small vector is quite fast, but you can obviously use pointer. Please note that they do not retain CCObjects passed to them, but check if they are nullptr before making a call.

So after spending some time with those delegates and many discussions with Dawid Drozd I’d come to following conclusions:* they aren’t entirely type-safe. You can f.e. create a delegate with a pointer to CCObject and some method from CCNode. I’d cause an Undefined Behavior.* they aren’t predictable: the order of adding functors and methods doesn’t change the calling order - methods are always invoked before functors.* they are overly complicated: one usually doesn’t need to keep many methods and functors at once* keeping methods and functors without a solution to manage their call priority is kinda useless

Hence, I’ve decided to simplify them and take care of correctness, rather than extending them. Now they just like the old-preprocessor-and-macro-based cocos callback, but they are extremely robust while being super-easy to use.

So, as you can see, you don’t even need to manually specify return type and arguments’ types, they can be automatically deduced from method’s signature by the compiler.

Now, it would be awesome to have some action like CCCallFunAction that would take a callback (and additional params). It’d be both simpler and powerful than old CCCallFunc.I’m going to try creating a prototype tomorrow.

after some intensive use of my callbacks in our projects they’ve changed a bit. Now the template parameter follows std::function convention and there is an option to bind functions, static methods and non-capturing lambdas (essentially the same things).The code is still available under the same link: https://gist.github.com/kuhar/8163865

I’ve done some research about callback in general and I’ve found out that current cocos 3.0 “callbacks” based on std::function and std::bind are tremendously slow when compared to my implementation.The test was run on Windows machine with i7 processor with the following includes:cocos2d.h (mocked): http://wklej.org/hash/d2e0603ac66/Callback.h: https://gist.github.com/kuhar/8163865

Thanks for sharing your code. I think in cocos2d-x v3.0 we are covering most of your ideas, since the API uses std::function instead of the old target/delegate pattern.

Regarding the performance tests, could you try the following ?

split the creation of the std::function from dispatching the callback.

I think that creating a std::function object is expensive because you are basicaly creating a new object. And when you use target/selector, you just basically pass two addresses.

Regarding dispatching, I think that both of them should have a similar performance, probably target/delegate could be slightly faster, but for sure, not 20x faster. Well, I could be wrong, but if that happens, the the compiler has a serious bug.

So, if I understood you correctly, after removing the second loop in each test I get 26ms and 75ms (2.88 x slower) on VC 12.1 and 9ms, 20ms on GCC 4.8 (2.22 x slower). All tests with O2.

But I think that creatnig/reassigning callbacks is pretty common when you use it as an alternative to CCNotifiactionCenter (and in similar cases) and it should not be undervalued. In such scenarios performance may be crucial. And the difference should be even greater when you’d store callback inside a vector, because of the std::function heap usage, thus harder to cache.

And probably other parts.In general, those APIs are “create once / dispatch multiple times”. So, yes, in v3.0 you pay a penalty for creating the callbacks, but you only pay a small penalty in the dispatching.

And what you gain is a more flexible API.

And you are correct about the heap. It is more expensive (memory-wise) to store an std::function than 2 longs. Although I don’t think this will be a big drawback.

The only gain that I can see is the ability to use capturing lambdas, which is not so useful in cocos IMHO. Edit: And they are not base-class dependent, but virtually all classes derive from CCObject, so it doesn’t matter.

>2 longsSize of a member function pointer is implementation-defined, even up to 20B on VC.