zoukankan      html  css  js  c++  java
  • 【C++11 新特性】bind(二)

    一、C++11为什么要引入std::bind?

    C++11 引入了std::bind,顾名思义,是用来绑定函数调用的某些参数的。std::bind能改造现有函数,生成新的函数。举例说明,现在有这么个函数声明:

    int f(int a, int b);
    

    我现在需求,我要一个有 2 个 int 类型参数的函数,并且第二个参数默认为 2。你可千万不要屁颠屁颠的在去写一个f(int i, int i = 2),这里std::bind的作用体现出来了,看:

    std::bind(&f, std::placeholders::_1, 2);
    

    好了,std::bind之后的返回值,那就可以拜托给我们的std::funtion同学了,我们定义个函数类型:

    std::function<int(int,int)> fun = std::bind(&f, std::placeholders::_1, 2);
    

    std::bind的返回值给 fun,于是我们就生成了一个 b 强制为 2,只有 1 个int a参数的 fun 新函数。

    最后要说一句,std::bind返回后的函数和原函数是 2 个完全不同的函数,这个你可以通过打印他们的内存地址看出来,这个就交给各位看官自己去实现了。

    二、概述

    std::bind函数定义在头文件<functional>中,是一个函数模板,它就像一个函数适配器,接受一个可调用对象(callable object),生成一个新的可调用对象来“适应”原对象的参数列表。

    使用std::bind可以将可调用对象和参数一起绑定,绑定后的结果使用std::function进行保存,并延迟调用到任何我们需要的时候,所以经常用来实现回调函数

    std::bind通常有两大作用:

    • 将可调用对象与参数一起绑定为另一个std::function供调用
    • 将 n 元可调用对象转成 m(m < n) 元可调用对象,绑定一部分参数,这里需要使用std::placeholders

    三、函数原型

    std::bind函数有两种函数原型,定义如下:

    template <class Fn, class... Args>
    /* unspecified */ bind (Fn&& fn, Args&&... args);
    
    template <class Ret, class Fn, class... Args>
    /* unspecified */ bind (Fn&& fn, Args&&... args);
    

    1. 函数模板说明

    • 基于参数fn返回一个函数对象,并且以args参数绑定为函数对象的参数。
    • 每个参数要么绑定一个参数值,要么绑定为一个std::placeholders(占位符,如 _1, _2, ..., _n)。
    • 如果参数绑定成一个值,那么返回的函数对象将总使用绑定的参数值做为调用参数,即调用传入参数将不起作用;如果参数绑定为std::placeholders,那么返回的函数对象在被调用时需要传入实时参数,参数填充的位置即由placeholder指定的序号。

    2. 函数模板参数说明

    • fn:可调用的函数对象,比如函数对象、函数指针、函数引用、成员函数或者数据成员函数。
    • args:需要绑定的函数的参数列表,使用命名空间占位符std::placeholders::_1std::placeholders::_2标志参数,其中std::placeholders::_1标志为参数列表中的第一个参数,std::placeholders::_2标志参数列表中的第二个参数,std::placeholders::_3标志参数列表中的第三个参数,以此类推。

    3. 函数模板返回值说明

    返回一个函数对象,该函数在调用时使用参数列表args来调用fn。如果fn是指向类的成员函数,则返回函数第一个参数应该是该类的成员、或者成员对象的引用、或者是成员对象的指针。

    四、示例

    #include <iostream>
    #include <functional>
    
    // 普通函数
    int testFun(int a, int b) {
    	return a + b;
    }
    
    // Lambda表达式
    auto lamdaExps = [](int a, int b) {
    	return a + b;
    };
    
    // 仿函数
    class Functor {
    public:
    	int operator()(int a, int b) {
    		return a + b;
    	}
    };
    
    // 1.类成员函数
    // 2.类静态成员函数
    class TestClass
    {
    public:
    	int classMemberFun(int a, int b) { return a + b; }
    	static int staticMemberFun(int a, int b) { return a + b; }
    };
    
    int main() {
    	// 绑定普通函数(使用占位符先占位,然后执行时再传参)
    	auto bindFun = std::bind(&testFun, std::placeholders::_1, std::placeholders::_2);
    	int ret = bindFun(10, 5);
    	std::cout << "普通函数_1:" << ret << std::endl;
    	// 绑定普通函数(也可以只使用一个占位符来占位,指定一个参数)
    	auto bindFun2 = std::bind(&testFun, std::placeholders::_1, 8);
    	ret = bindFun2(10);
    	std::cout << "普通函数_2:" << ret << std::endl;
    
    	// 绑定Lambda表达式
    	auto bindFun3 = std::bind(lamdaExps, std::placeholders::_1, std::placeholders::_2);
    	ret = bindFun3(10, 20);
    	std::cout << "Lambda表达式:" << ret << std::endl;
    
    	// 绑定仿函数
    	Functor testFunctor;
    	auto bindFun4 = std::bind(testFunctor, std::placeholders::_1, std::placeholders::_2);
    	ret = bindFun3(10, 30);
    	std::cout << "仿函数:" << ret << std::endl;
    
    	// 绑定类成员函数
    	TestClass testObj;
    	auto bindFun5 = std::bind(&TestClass::classMemberFun, testObj, std::placeholders::_1, std::placeholders::_2);
    	ret = bindFun5(10, 40);
    	std::cout << "类成员函数:" << ret << std::endl;
    	// 绑定类静态成员函数
    	auto bindFun6 = std::bind(&TestClass::staticMemberFun, std::placeholders::_1, std::placeholders::_2);
    	ret = bindFun6(10, 50);
    	std::cout << "类静态成员函数:" << ret << std::endl;
    
    	return 0;
    }
    

    结果如下:

    普通函数_1:15
    普通函数_2:18
    Lambda表达式:30
    仿函数:40
    类成员函数:50
    类静态成员函数:60
    

    关于绑定模块函数、模板类的示例可以参考:C++11 - std::bind简要介绍以及可绑定函数的几种形式总结


    参考:

    浅谈std::function和std::bind

    C++11中的std::bind


  • 相关阅读:
    【k8s】Volume-persistentVolumeReclaimPolicy
    【k8s】Volume-pv
    【k8s】Secret-生成环境变量
    【k8s】Volume-nfs
    【k8s】Volume-hostPath
    【k8s】Volume-emptyDir
    【k8s】Volume-downwardAPI
    【k8s】Volume-Secret
    【k8s】Volume-ConfigMap-file
    SQL SERVER 列转行
  • 原文地址:https://www.cnblogs.com/linuxAndMcu/p/14575979.html
Copyright © 2011-2022 走看看