2022-09-22 std::bind 使用时使用函数传参的问题

前言

前几天用到了std::bind(),就随便在baidu上搜了一下就开始使用了,结果使用过程中才发现百度上搜到的资料都巨坑,最终还是在https://en.cppreference.com/w/cpp/utility/functional/bind 找到最正式的说明,才解决问题

一、先说明问题

上段代码:

class BindTest
{
public:
    BindTest() { m_func = std::bind(&BindTest::printComp, this, getComp()); }

    void printComp(int num) { qDebug() << num; }

    void print() { m_func(); }

    void setComp(int comp) { m_comp = comp; }
    int getComp() { return m_comp; }

private:
    int m_comp = 0;
    std::function<void()> m_func;
};


    BindTest tt;
    tt.print(); // 0
    tt.setComp(100);
    tt.print(); // 0

第二个print 是希望打印出100,但传值是传的0,
查手册才知道,bind 的时候这种方式只传值,即使绑定时,绑定m_comp,结果也一样

    BindTest() { m_func = std::bind(&BindTest::printComp, this, m_comp ); }

二、解决方式

方式1:

    BindTest() { m_func = std::bind(&BindTest::printComp, this, std::cref(m_comp)); }

此方式只能引用已有的变量,如果遇到必须使用函数来传对的,此方式就不行了

方式2:

    BindTest()
    {
        m_func = std::bind(&BindTest::printComp, this, std::bind(&BindTest::getComp, this));
    }

这种方式可以以函数来传参。。

特别是对于静态函数,此方法最好用

static int comp(){
	reutrn s_comp;
}
    BindTest()
    {
        m_func = std::bind(&BindTest::printComp, this, std::bind(comp));
    }

三、lambda 的方式替换bind

此小节由 2022-10-26 22:04:52 更新
其实使用lambda来替换bind,使用起来更简单,而且看起来更明了。
如第二小节中的代码

 m_func = std::bind(&BindTest::printComp, this, std::bind(comp));

可以改写为下方式

m_func = [&](){ printComp(getComp());};

也可以写成:

m_func = [&](){ printComp(m_comp);};

对于需要带参数的,如:

void ppp(int s){
	...
}
m_func = [](int param){ ppp(param);};

这样可以避免第一小节中的问题,
注意,lambda中的[ ]里的参数要取决于{} 里函数所属对象,如=,&,this,对象等。
参考如下:
https://www.apiref.com/cpp-zh/cpp/language/lambda.html

官方手册代码

#include <random>
#include <iostream>
#include <memory>
#include <functional>
 
void f(int n1, int n2, int n3, const int& n4, int n5)
{
    std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << '\n';
}
 
int g(int n1)
{
    return n1;
}
 
struct Foo {
    void print_sum(int n1, int n2)
    {
        std::cout << n1+n2 << '\n';
    }
    int data = 10;
};
 
int main()
{
    using namespace std::placeholders;  // 对于 _1, _2, _3...
 
    // 演示参数重排序和按引用传递
    int n = 7;
    // ( _1 与 _2 来自 std::placeholders ,并表示将来会传递给 f1 的参数)
    auto f1 = std::bind(f, _2, 42, _1, std::cref(n), n);
    n = 10;
    f1(1, 2, 1001); // 1 为 _1 所绑定, 2 为 _2 所绑定,不使用 1001
                    // 进行到 f(2, 42, 1, n, 7) 的调用
 
    // 嵌套 bind 子表达式共享占位符
    auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5);
    f2(10, 11, 12); // 进行到 f(12, g(12), 12, 4, 5); 的调用
 
    // 常见使用情况:以分布绑定 RNG
    std::default_random_engine e;
    std::uniform_int_distribution<> d(0, 10);
    std::function<int()> rnd = std::bind(d, e); // e 的一个副本存储于 rnd
    for(int n=0; n<10; ++n)
        std::cout << rnd() << ' ';
    std::cout << '\n';
 
    // 绑定指向成员函数指针
    Foo foo;
    auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1);
    f3(5);
 
    // 绑定指向数据成员指针
    auto f4 = std::bind(&Foo::data, _1);
    std::cout << f4(foo) << '\n';
 
    // 智能指针亦能用于调用被引用对象的成员
    std::cout << f4(std::make_shared<Foo>(foo)) << '\n'
              << f4(std::make_unique<Foo>(foo)) << '\n';
}

输出

2 42 1 10 7
12 12 12 4 5
1 5 0 2 0 8 2 2 10 8
100
10
10
10

总结

重点还是看官方手册:
https://en.cppreference.com/w/cpp/utility/functional/bind

https://www.apiref.com/cpp-zh/cpp/utility/functional/bind.html

两个都一样,只是一个中文一个是英文

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值