I’m going to state that traditional delegates are boring. They address the “problem” of form while doing nothing to address function. What is more interesting is a system of delegates that is friendly to concurrent programming.
std::future is the C++11 industry solution but in my opinion they are bulky and hard to read. Instead, I prefer my own system which is almost just like the juce::ListenerList, with the twist that when you call addListener(), you can specify on which thread you would like to be called (!). Everything is handled for you.
You can see how this works, in the vf::Listeners implementation in VFLib
The heavy lifting in this implementation is the part where all conflicts related to calling listeners that are about to be removed, or have been removed, from other threads are resolved - plus a lock free and mostly wait-free garbage collected free store which avoids ABA without using 64-bit CAS:
Listeners< ListenerClass > Class Template Reference
void audioDeviceIOCallback (const float** inputChannelData, int numInputChannels, float** outputChannelData, int numOutputChannels, int numSamples)
// Notify listeners.
listeners.call (&Listener::onOutputLevelChanged, newOutputLevel);
Note the clear syntax in listeners.call(). Don’t be fooled, this ain’t the juce::ListenerList, all Listener objects which register via addListener() get to specify an additional CallQueue on which they would like the member function to get invoked.