首页 > 其他分享 >std::bind

std::bind

时间:2022-11-06 22:57:04浏览次数:46  
标签:std 示例 int bind 绑定 include

目录

std::bind

1. 参数重排序和引用传递(argument reordering and pass-by-reference)

1.1 示例代码

#include <iostream>
#include <functional>

void func(int n1, int n2, int n3, const int& n4, int n5)
{
    std::cout << "n1: " << n1 << std::endl;
    std::cout << "n2: " << n2 << std::endl;
    std::cout << "n3: " << n3 << std::endl;
    std::cout << "n4: " << n4 << std::endl;
    std::cout << "n5: " << n5 << std::endl;
}

int main()
{
    using namespace std::placeholders;  // for _1, _2, _3...

    int n = 7;
    auto bFunc = std::bind(func, _2, 43, _1, std::cref(n), n);
    n = 99;
    bFunc(33, 55, 1001);

    return 0;
}

/* run output:
n1: 55
n2: 43
n3: 33
n4: 99
n5: 7
*/

1.2 解析

1.2.1 参数重排序

从示例第18行分析,绑定函数func时,func函数五个参数:

第一个参数:_2,表示取实参列表中第二个值;结果n1等于55。

第二个参数:43,表示是个常量值,即固定值;结果n2等于43。

第三个参数:_1,表示取实参列表中第一个值;结果n3等于33。

第四个参数:std::cref(n),表示引用传递,引用n变量的值,即在调用函数前,n变为多少将来就取多少。

​ 第19行,我们将n赋值为99。结果n4等于19。

第五个参数:n,表示值传递,即就取此时此刻n变量的值,常量值为7,固定值。结果n5等于7。

注意:实参列表中第三个值1001没有使用到,1001等价于的std::placeholders_3值。

因为绑定时只使用到std::placeholders_1和std::placeholders_2的值。

1.2.2 引用传递

std::cref() 表示常量引用

std::ref 表示引用

1.3 使用lambda实现同样效果

1.3.1 示例代码

#include <iostream>

void func(int n1, int n2, int n3, const int& n4, int n5)
{
    std::cout << "n1: " << n1 << std::endl;
    std::cout << "n2: " << n2 << std::endl;
    std::cout << "n3: " << n3 << std::endl;
    std::cout << "n4: " << n4 << std::endl;
    std::cout << "n5: " << n5 << std::endl;
}

int main()
{
    int n = 7;
    auto lambda = [&ncref = n, n](auto a, auto b, auto unused) {
        func(b, 43, a, ncref, n);
    };
    n = 99;
    lambda(33, 55, 1001);

    return 0;
}

/* run output:
n1: 55
n2: 43
n3: 33
n4: 99
n5: 7
*/

2. 嵌套绑定子表达式共享占位符(nested bind subexpressions share the placeholders)

2.1 示例代码

#include <iostream>
#include <functional>

int g(int n1)
{
    return n1;
}

void func(int n1, int n2, int n3, const int& n4, int n5)
{
    std::cout << "n1: " << n1 << std::endl;
    std::cout << "n2: " << n2 << std::endl;
    std::cout << "n3: " << n3 << std::endl;
    std::cout << "n4: " << n4 << std::endl;
    std::cout << "n5: " << n5 << std::endl;
}

int main()
{
    using namespace std::placeholders;  // for _1, _2, _3...

    auto bFunc2 = std::bind(func, _3, std::bind(g, _2), _2, 4, 5);
    bFunc2(10, 11, 12);

    return 0;
}

/* run output:
n1: 12
n2: 11
n3: 11
n4: 4
n5: 5
*/

2.2 解析

从示例第22行分析,绑定函数func时,func函数五个参数:

第一个参数:_3,表示取实参列表中第三个值;结果n1等于12。

第二个参数:std::bind(g, _2),嵌套子表达式,绑定函数g,函数g的参数取值为std::placeholders_2,即实参列表中第二个值;g函数未对参数值改变。

结果n2等于11。

第三个参数:_2,表示取实参列表中第二个值;结果n3等于11。注意:与第二个参数共享std::placeholders_2实参列表中第二个值。

第四个参数:4,表示是个常量值,不论什么时候都不变化,即固定值;结果n4等于4。

第五个参数:5,表示是个常量值,不论什么时候都不变化,即固定值;结果n4等于5。

注意:实参列表中第一个值10没有使用到,10等价于的std::placeholders_1值。

因为绑定时只使用到std::placeholders_2和std::placeholders_3的值。

3. 绑定一个随机数生成器于均匀离散分布器上(binding a RNG with a distribution)

3.1 示例代码

#include <random>
#include <iostream>
#include <functional>

int main()
{
    // 生成随机数方式一:生成器作为参数
    {
        std::default_random_engine e;  //C++11提供的伪默认随机数生成器
        std::uniform_int_distribution<> d(0, 10); // 均匀生成(0,10)的离散整数
        for (int n = 0; n < 10; ++n)
        {
            std::cout << d(e) << ' ';  //生成一个随机数
        }
        std::cout << std::endl;
    }
    // 生成随机数方式二:利用std::bind进行绑定
    {
        std::default_random_engine e;
        std::uniform_int_distribution<> d(0, 10);
        auto rnd = std::bind(d, e); // a copy of e is stored in rnd
        for (int n = 0; n < 10; ++n)
        {
            std::cout << rnd() << ' ';
        }
    }

    return 0;
}

/* run output:
6 3 10 9 4 7 0 6 5 4
6 3 10 9 4 7 0 6 5 4
*/

3.2 解析

std::default_random_engine C++11提供的一个伪默认随机数生成类。

std::uniform_int_distribution<> d(0, 10); 生成随机整型数,均匀分布于[0, 10],根据离散概率函数分析。

4.绑定到成员函数的指针(bind to a pointer to member function)

4.1 示例代码

#include <iostream>
#include <functional>

struct Foo
{
    void print_sum(int n1, int n2)
    {
        std::cout << n1 + n2 << '\n';
    }
};

int main()
{
    using namespace std::placeholders;  // for _1, _2, _3...

    Foo foo;
    // 方式一
    std::cout << "方式一:";
    foo.print_sum(95, 5);
    // 方式二
    std::cout << "方式二:";
    std::function<void(int)> f2 = std::bind(&Foo::print_sum, &foo, 95, _1);
    f2(5);
    // 方式三
    std::cout << "方式三:";
    auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1);
    f3(5);

    return 0;
}

4.2 解析

绑定类的成员函数,必须首先明确绑定的类对象,类只是"形",对象才是“神”。

或者可以理解为:绑定必须通过实实在在的东西建立关系。即类Foo的对象foo的成员函数print_sum。

95为print_sum成员函数的第一个参数值,即为常量值,固定值。

std::placeholders_1即将实参第一个参数值作为print_sum成员函数的第二个参数值。

所以如上,第23、27行两种方式调用,均等价于第19行的效果。 估输出值均为100。

5.绑定到成员函数指针包装器mem_fn(bind to a mem_fn that is a pointer to member function)

5.1 示例代码

#include <iostream>
#include <functional>

struct Foo
{
    void print_sum(int n1, int n2)
    {
        std::cout << n1 + n2 << '\n';
    }
};

int main()
{
    using namespace std::placeholders;  // for _1, _2, _3...

    Foo foo;
    // 方式一
    std::cout << "方式一:";
    foo.print_sum(95, 5);
    // 方式二
    std::cout << "方式二:";
    std::function<void(int)> f2 = std::bind(&Foo::print_sum, &foo, 95, _1);
    f2(5);
    // 方式三
    std::cout << "方式三:";
    auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1);
    f3(5);

    // 方式四(std::mem_fn && auto)
    {
        std::cout << "方式四:";
        auto ptr_to_print_sum = std::mem_fn(&Foo::print_sum);
        auto f4 = std::bind(ptr_to_print_sum, &foo, 95, _1);
        f4(5);
    }

    // 方式五(std::mem_fn && 类型全称)
    {
        std::cout << "方式五:";
        std::_Mem_fn<void(Foo::*)(int, int)> ptr_to_print_sum = std::mem_fn(&Foo::print_sum);
        auto f5 = std::bind(ptr_to_print_sum, &foo, 95, _1);
        f5(5);
    }

    return 0;
}

/* run output:
方式一:100
方式二:100
方式三:100
方式四:100
方式五:100
*/

5.2 解析

std::mem_fn 这里的mem不是memory的缩写,而是member的缩写,即指类的成员member,而fn就是指function,其完整的单词应该是 member function,即mem_fn作用是用来包装类成员函数指针。

方式四和方式五无本质差异,方式五主要把ptr_to_print_sum变量的真实类型展现出来。便于理解和学习记忆。

6. 绑定类成员变量

6.1 示例代码

#include <iostream>
#include <functional>

struct Foo
{
    int m_nData = 100;
};

int main()
{
    using namespace std::placeholders;  // for _1, _2, _3...

    Foo foo;
    {
        // 方式一
        auto f1 = std::bind(&Foo::m_nData, _1);
        std::cout << "方式一 || 对象foo的成员变量m_nData的值:" << f1(foo) << '\n';
    }

    {
        // 方式二
        auto f2 = std::bind(&Foo::m_nData, _1);
        std::cout << "方式二 || 对象foo的成员变量m_nData的值:" << f2(&foo) << '\n';
    }

    {
        // 方式三
        auto ptr_to_data = std::mem_fn(&Foo::m_nData);
        auto f3 = std::bind(ptr_to_data, _1);
        int value = f3(&foo);
        std::cout << "方式三 || 对象foo的成员变量m_nData的值:" << value << '\n';
    }

    {
        // 方式四
        auto ptr_to_data = std::mem_fn(&Foo::m_nData);
        auto f4 = std::bind(ptr_to_data, _1);
        int value = f4(std::make_shared<Foo>(foo));
        std::cout << "方式四 || 对象foo的成员变量m_nData的值:" << value << '\n';
    }

    {
        // 方式五
        auto ptr_to_data = std::mem_fn(&Foo::m_nData);
        auto f5 = std::bind(ptr_to_data, _1);
        int value = f5(std::make_unique<Foo>(foo));
        std::cout << "方式五 || 对象foo的成员变量m_nData的值:" << value << '\n';
    }

    return 0;
}

/* run output:
方式一 || 对象foo的成员变量m_nData的值:100
方式二 || 对象foo的成员变量m_nData的值:100
方式三 || 对象foo的成员变量m_nData的值:100
方式四 || 对象foo的成员变量m_nData的值:100
方式五 || 对象foo的成员变量m_nData的值:100
*/

6.2 解析

方式一:常用的方式(推荐使用)。

方式二:调用时传入对象指针,方式一本质其实与方式二相同。

方式三:利用std::mem_fn,可见std::mem_fn不仅仅可以应用在类成员函数上,也可以利用在类成员变量上。

方式四:通过智能指针std::make_shared

方式五:通过智能指针std::make_unique

标签:std,示例,int,bind,绑定,include
From: https://www.cnblogs.com/Braveliu/p/16864524.html

相关文章

  • js中的call,apply与bind
    call,apply,bind都是一种方法。一,call()①:call()是可以调用函数的。1functionfn(){2console.log(12)3}45fn.call()//12 ②:通过给call()内部传......
  • DNS服务器部署-bind
    @目录简单安装部署(ubuntu)centos客户端进行测试自定义域名配置配置正向解析配置反向解析centos客户端测试安装部署(centos)自定义域名配置ubuntu客户端测试配置域名解析多个地......
  • Linux安装JDK,解压报错:gzip: stdin: not in gzip format
    问题描述在Linux安装JDKtar-zxvf命令解压时,报错,无法解压报错内容:gzip:stdin:notingzipformattar:Childreturnedstatus1tar:Errorisnotrecoverable:e......
  • 第2-1-2章 传统方式安装FastDFS-附FastDFS常用命令
    目录3安装配置3.1安装GCC3.2安装libevent3.3安装libfastcommon3.4安装FastDFS3.5安装fastdfs-nginx-module3.5安装Nginx3.6配置FastDFSTracker3.5.1配置Tracker3......
  • baidu_std协议了解
    转自:https://github.com/apache/incubator-brpc/blob/master/docs/cn/baidu_std.md1.介绍baidu_std是一种基于TCP协议的二进制RPC通信协议。它以Protobuf作为基本的数据......
  • robotframework自动化测试框架实战教程:测试数据文档工具(Testdoc)
    生成文档的数据源可以是单个文件,单个目录,也可以是多个文件和目录.所有这些情况,最后那个参数都必须是最终文档输出要写入的文件.基本用法python-mrobot.testdoc......
  • js的bind 的原理
    js的bind方法主要绑定this的指向bind方法也会返回是个bind后的函数。知道它功能我们就可以自定义bind功能letobject={name:'jeff'}functionfn(){console.log(thi......
  • 第2-1-1章 FastDFS分布式文件服务背景及系统架构介绍
    目录1背景1.1为什么需要分布式文件服务1.1.1单机时代1.1.2独立文件服务器1.1.3分布式文件系统1.2什么是FastDFS2系统架构2.1Tracker集群2.2Storage集群2.3Storag......
  • opencv遇到std::bad_alloc异常
    配置opencv环境时遇到的,首先注意解决方案平台是x64而不是x86,然后属性管理器->Debug|64右键属性->链接器->输入->附加依赖项中,把opencv_world460.lib(不同版本数字不同,位......
  • t-testdisk 分区恢复
    安装配置好yum源,直接使用yum​​yuminstalltestdisk-y​​​安装好之后直接运行​​testdisk​​或者​​testdisk/dev/sdx​​进入如下界面,选择​​create​​进行日......