首页 文章

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

提问于
浏览
4

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

  • 使用std :: bind将std :: function绑定到其参数(使用variadic模板获取),然后再调用它

  • 将参数包转换为元组,存储和std :: function,然后再次将元组解包为多个args并使用该函数调用函数

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

谢谢!

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

2 回答

  • 0

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

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

  • 0

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

    例如:

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

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

相关问题