C++11绑定std::函数与存储元组和解包

C++ 11 bound std::function vs storing tuple and unpacking

本文关键字:元组 和解 存储 函数 绑定 std C++11      更新时间:2023-10-16

首先,我对C++11还比较陌生,所以如果我遗漏了什么,请原谅我的疏忽。所以我想做的基本上是让调用者传入一个函数和该函数的任意#个参数,将其存储起来,然后稍后异步调用

  • 使用std::bind将std::函数绑定到其参数(使用varadic模板获得),然后稍后调用它
  • 将参数包转换为元组,存储该元组和std::函数,然后再次将元组解压缩为多个args,并使用该参数调用函数

问题是,一种方式比另一种方式好吗?两者相比是否有优点/缺点/性能优势?

谢谢!

EDIT:根据要求,这里有一个澄清,第一种情况是更早期的绑定,在调用方传递参数后,我立即将其绑定到函数,并存储绑定的函数以供稍后调用。第二种情况是,我分别存储func和args,并在以后必须调用时用args调用函数。所以问题是哪个性能/代码大小/样式等更好?

接受具有适当签名的std::function<...>,并将其存储以便稍后回调。让调用者决定如何创建/填充参数。例如,

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

如果您不绝对要求回调的类型擦除,那么最好的性能是将代码参数化为函子类型。例如:

#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) << "nn";
}
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);});
}

在某些情况下,避免类型擦除是不可能的,而在其他情况下,则需要跳过重重关卡。这样做是否值得取决于具体情况。

第三种可能性是将绑定所有参数的责任转移到调用者,只保留一个带有您想要调用的签名的std::函数。

例如:

struct Silly
{
using Callback = std::function<void()>;
void registerCallback(Callback cb) { callback_ = std::move(cb); }
Callback callback_;
};

通过这种方式,很明显,调用者有责任处理参数的生存期、值与引用语义等。