I have a function which takes an object and invokes various callback functions on it as its output. Example:
template<typename T>
void iterateInParallel(vector<int> const& a, vector<int> const& b, T && visitor)
{
// sometimes invokes visitor.fromA(i)
// sometimes invokes visitor.fromB(i)
// sometimes invokes visitor.fromBoth(i, j)
}
(Don't get caught up in exactly what the function does, it's an example and not relevant here.)
Now, when writing code to use a function which takes a callback object, I'll often use a local lambda with a default by-ref capture to keep my code tight and readable.
int sum = 0;
int numElems = 0;
someFunctionTakingACallback(args, [&](int x) {sum += x; numElems++; });
That's a lot nicer than the old functor approach, where I'd define a class for the purpose which took refs to sum
and numElems
in its constructor. And like the functor approach, it generally has zero runtime cost, since the code for the callback is known when instantiating the function.
But a lambda is but one function, so it's not workable for the iterateInParallel
method above; I'm back to copying refs around.
So what I'm looking for, is a means of getting roughly the level of convenience, performance, and idiomaticity I have from lambdas' default-capture, while still being able to invoke multiple types of callbacks.
Options I've considered:
- Passing multiple callback functions. This isn't too bad, and is usually what I've gone for. But it's easy to get the parameter order mixed up, and it can really bloat the argument list. It's also less self-documenting, since the name of the callbacks are nowhere in the user code.
- Rewriting the inner function so that it invokes one callback, with parameters to help define what kind of callback it is. Ugly, hacky, and not the sort of thing a respectable programmer would do.
- Passing a structure with a whole bunch of
std::function
s in it. I get the feeling that I could get this to look okay, but I also get the feeling that it would end up doing heap allocations and per-invocation indirection. - Something wacky involving the preprocessor. Heaven forfend.