zoukankan      html  css  js  c++  java
  • functional仿函数(函数对象),std::bind,std::invoke

    中文标准库:头文件<functional>

    函数指针与回调函数

    lambda:匿名函数

    function底层分配机制:暴力malloc,实时分配性能低下。

    std::function<int(int, int)> f = lambda/普通函数/类函数/函数对象/模版函数/bind/

    一、标准库中的常用函数对象

    • std::bit_or

    • std::equal_to

    • std::plus

    • std::bind2nd

    • std::bind -> placeholders

    • std::greater

    • std::less

    运算符

    二、仿函数的优点

    • 仿函数是对象,可以拥有成员函数和成员变量,即仿函数拥有状态(states)

    • 每个仿函数都有自己的类型

    • 仿函数通常比一般函数快(很多信息编译期确定)

    三、仿函数(std::function)和函数指针

    仿函数是一个,是数据以及对数据操作的行为的集合,要成为仿函数必须重载()。函数指针是无法保存数据的,所以仿函数比函数指针功能更强,因为它可以保存数据,这一特性,是函数指针无法比拟的优势。

    转载:std::function和std::bind的使用 讲的挺全面

    #include <iostream>
    #include <functional>
    
    int add(int a, int b)
    {
        return a + b;
    }
    
    int main()
    {
        typedef int(*fun)(int, int);     //函数指针,指针名:fun,参数为:int,int返回值为:int
        std::function<int(int, int)> b;  //std::function仿函数,函数对象名:b,参数为:int,int返回值为:int
    
        fun a = add;
        b = add;
        std::cout << a(2, 3) << '
    ';
        std::cout << b(3, 4) << '
    ';
    
        return 0;
    }
    

    std::function指向类成员函数,静态成员函数和普通函数用法一致。

    #include <functional>
    
    class Test {
    public:
        int fun(int x, int y) 
        {
            return x + y;
        }
    };
    
    int main()
    {
        Test test;
        // 方式1:fun1的类型可以为auto
        std::function<int(int, int)> fun1 = std::bind(&Test::fun, test,std::placeholders::_1, std::placeholders::_2);
        int result1 = fun1(1, 2);
    
        // 方式2:fun2的类型必须明确指定,不能为auto
        std::function<int(Test, int, int)> fun2 = &Test::fun;
        int result2 = fun2(test, 1, 2);
    
        return 0;
    }
    

    std::mem_fn从成员指针创建出函数对象

    简单理解就是利用一个成员函数生成一个函数对象

    std::mem_fn中文标准库

    四、std::function和std::bind

    std::function是一个类,std::bind是一个函数(具体可以看functional头文件中的定义)

    placeholders是占位符。表示新的函数对象中参数的位置(_2:表示第二个实参)。当调用新的函数对象时,新函数对象会调用被调用函数,并且其参数会传递到被调用函数参数列表中持有与新函数对象中位置对应的占位符。
    例如:

    void function(arg1, arg2, arg3, arg4, arg5)
    {
    	//do something
    }
    auto g = bind(function, a, b, _2, c, _1);
    

    新的函数对象:g 被调用函数:function

    当调用函数对象g时候,函数对象g会调用function函数,并把其参数传给function函数,g的第一个参数会传给function的持有占位符_1的位置,即arg5。第二个参数会传给function的持有占位符_2的位置,即arg3。

    g(X,Y);相对于调用:function(function,a,b,Y,c,X);

    其中的arg1,arg2,arg4已经被绑定到a,b,c上。

    placeholders是一个命名空间,其本身定义在std命名空间中。placeholder中有名字_n (1,2,3,4,……n)。为了使用这些名字,两个命名空间都必须写上。例如:

    using namespace std::placeholders::_1;

    与bind函数一样,placeholders命名空间也定义在functional中。

    转载:标准库bind函数中使用占位符placeholders

    #include <iostream>
    #include <functional>
    #include <string>
    
    using namespace std;
    
    int TestFunc(int a, string c, float f)
    {
    	cout << a << endl;
    	cout << c << endl;
    	cout << f << endl;
    
    	return a;
    }
    
    int main()
    {
    	auto bindFunc1 = bind(TestFunc, std::placeholders::_1, "abc", 66.66);
    	bindFunc1(10);
    
    	cout << "================================
    ";
    
    	bindFunc1(6.6, "sss", "ggg");  //实参个数可以多于placeholders的个数,返回值为auto才可以这样
    	//返回值为:function<int(int, string, float)> 则实参必须为:int,string,float且参数个数必须为3
    
    	cout << "=================================
    ";
    
    	auto bindFunc2 = bind(TestFunc, std::placeholders::_2, std::placeholders::_1, 77.77);
    	bindFunc2("xxx", 10);
    	//bindFunc2("yyy");  //错误,实参个数不能少于placeholders个数,相同的placeholder算一个
    
    	cout << "=================================
    ";
    
    	auto bindFunc3 = bind(TestFunc, std::placeholders::_2, std::placeholders::_1, std::placeholders::_2);
    	bindFunc3("ss", 2);  //只有两个placeholders::_1,_2
    
    	cout << "=================================
    ";
    
    	auto bindFunc4 = bind(TestFunc, std::placeholders::_3, std::placeholders::_2, std::placeholders::_1);
    	//bind相当于TestFunc(_3,_2,_1); _3表示bindFunc4的实参中的第三个参数。
    	bindFunc4(5.5, "hhh", 2);  //实参类型根据bind中placeholders确定
    
    	return 0;
    }
    

    五、std::invoke

    中文标准库:std::invoke(有invoke使用方法)

    functional仿函数,std::bind,std::invoke,std::visit

    invoke简单理解就是用来调用函数的(普通函数,成员函数,访问数据成员,lambda,函数对象都可以),可以完美替代#define宏

    转发:函数调用的完美实现

    std::invoke_result用来获取调用函数地返回值类型。

    std::invoke_result

    #include <type_traits>
    #include <iostream>
    
    typedef int(FUN)(char,int,float);
    
    int main()
    {
    	std::invoke_result_t<FUN,double,float,int>  s;  //int
    
    	std::invoke_result<FUN, int, int, int>::type t; //int
    	t = 3;
    	s = 2;
    
    	return 0;
    }
    
  • 相关阅读:
    【Hello CC.NET】巧用模板简化配置
    【Hello CC.NET】自动化发布时 Web.config 文件维护
    Hello Jexus
    【Hello CC.NET】CC.NET 实现自动化集成
    SSE和WebSocket的用法和比较
    利用canvas实现鼠标跟随效果
    使用es6制作简单数独游戏
    ppt学习(3)
    ppt学习(2)
    ppt学习(1)
  • 原文地址:https://www.cnblogs.com/mmmmmmmmm/p/14804972.html
Copyright © 2011-2022 走看看