C ++ 11绑定std :: function vs存储元组和解包

时间:2014-01-07 20:37:13

标签: c++ c++11 std variadic-templates

首先,我对C ++ 11还是比较陌生的,所以如果我错过任何东西,请原谅我的疏忽。所以我要做的是基本上调用函数传递函数和该函数的任意参数#,将其存储起来然后稍后异步调用它。似乎有两个主要选择:

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

问题是,是否比另一种更好?是否有利益/利弊/绩效优势?

谢谢!

编辑:根据要求,这里有一个澄清,第一种情况是更早期的绑定,我在调用者传递它们时将args绑定到函数,然后我存储绑定的函数以便稍后调用。第二种情况是我分别存储func和args,然后在必须调用时使用args调用函数。所以问题是哪个是更好的性能/代码/样式/等?

2 个答案:

答案 0 :(得分:1)

接受带有相应签名的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);
}

最佳性能 - 如果您不绝对需要对回调进行类型擦除 - 将在functor类型上参数化您的代码。 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);});
}

在某些情况下避免类型擦除是不可能的,而在其他情况下则需要你跳过箍。是否值得这样做是情境化的。

答案 1 :(得分:0)

第三种可能性是将所有参数绑定到调用者的责任,并且只保留带有您要调用的签名的std :: function。

例如:

struct Silly
{
    using Callback = std::function<void()>;

    void registerCallback(Callback cb) { callback_ = std::move(cb); }

    Callback callback_;
};

这种方式很明显,调用者有责任处理参数的生命周期,值与参考语义等。