First off, I am still relatively new to C++11, so if I am missing anything, pardon my oversight. So what I am trying to do is basically have caller pass in a function and arbitrary # of arguments for that function, store that off and then call it asynchronously later on. And it seems there are 2 main options for this:
Question is, is one way better than the other? Are there pro/cons/performance benefits of one over the other?
Thanks!
EDIT: as requested, here is a clarification, the first case is more early binding where I bind args to function as soon as caller passes them on and I store the bound func to be called later. the 2nd case is where I store func and args separately and invoke function with the args later on when it has to be called. So question is which is better performance/codesize/style/etc?
Accept a std::function<...>
with the appropriate signature, store it to callback later. Let the caller decide how they prefer to create/populate the parameter. E.g.,
#include <functional>
#include <iostream>
std::function<int(int)> stored_f;
void set_callback(std::function<int(int)> f) {
stored_f = std::move(f);
}
void run_the_callback(int value) {
std::cout << stored_f(value) << '\n';
}
int f(int i) {
return i + 1;
}
int g(int a, int b) {
return a + b;
}
int main() {
// Plain old function pointer
set_callback(f);
run_the_callback(1);
// Use std::bind
set_callback(std::bind(g, 2, std::placeholders::_1));
run_the_callback(2);
// Use a lambda
set_callback([](int i){ return f(i) * g(i, i);});
run_the_callback(3);
}
Best performance - if you don't absolutely require type erasure of the callback - would be to parameterize your code on functor type. E.g.:
#include <functional>
#include <iostream>
template <typename Functor>
void do_stuff_and_callback_sometimes(Functor f) {
std::cout << f(1) << '\n';
// do some stuff, then
std::cout << f(2) << '\n';
// more work, and finally
std::cout << f(3) << "\n\n";
}
int f(int i) {
return i + 1;
}
int g(int a, int b) {
return a + b;
}
int main() {
// Plain old function pointer
do_stuff_and_callback_sometimes(f);
// Use std::bind
do_stuff_and_callback_sometimes(std::bind(g, 2, std::placeholders::_1));
// Use a lambda
do_stuff_and_callback_sometimes([](int i){ return f(i) * g(i, i);});
}
Avoiding type erasure is impossible in some situations, and in others will require you to jump through hoops. Whether or not it's worthwhile to do so is situational.