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


  • 相关阅读:
    201521044091《Java程序设计》第7周学习总结
    201521044091《java程序设计》第四次总结
    201521044091 《java程序设计》第八周学习总结
    201521044091 《Java程序设计》第5周学习总结
    201521044091 《Java程序设计》第2周学习总结
    201521044091 《Java程序设计》第3周学习总结
    MySQL设置字符集CHARACTER SET
    Create My MySQL configuration by Percona
    How to use jQuery to manipulate Cookies
    How to use OpenXml to import xml data to Sql server
  • 原文地址:https://www.cnblogs.com/linuxAndMcu/p/14575979.html
Copyright © 2011-2022 走看看