functional仿函数(函数对象),std::bind,std::invoke

摘要:
#includeclassTest{public:intfun{returnx+y;}};Intmain(){Testtest;//方法1:fun1的类型可以是autostd::function<int>fun1=std::bind;interresult1=fun1(1,2);//方法2:必须显式指定fun2的类型,并且不能是autostd::function<int>fun2=&Test::fun;intersult2=fun2;return0;}std::mem_ Fn要从成员指针创建函数对象,一个简单的理解是使用成员函数生成函数对象std::mem_ Fn中国标准库4。std::function和std::bindstd::functions是类,std::绑定是函数占位符。

中文标准库:头文件<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;
}

免责声明:文章转载自《functional仿函数(函数对象),std::bind,std::invoke》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇SQL触发器实例(下)android Activity介绍下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

bind函数的作用

  面向连接的网络应用程序分为客户端和服务器端。服务器端的执行流程一般为4步,客户端程序相对简单,一般需要两个步骤。 服务器端执行流程4步如下: (1)调用socket函数,建立一个套接字,该套接字用于接下来的网络通信。 (2)调用bind函数,将该套接字绑定到一个地址,并制定一个端口号, (3)调用listen函数,使用该套接字监听连接请求 (4)当请求...

【转载】JS中bind方法与函数柯里化

  原生bind方法   不同于jQuery中的bind方法只是简单的绑定事件函数,原生js中bind()方法略复杂,该方法上在ES5中被引入,大概就是IE9+等现代浏览器都支持了(有关ES5各项特性的支持情况戳这里ECMAScript 5 compatibility table),权威指南上提到在ES3中利用apply模拟该方法的实现(JS权威指南中函数...

使用lambda调用有参函数

package com.mayikt.service; /** * @ClassName YouShenInterface * @Author 蚂蚁课堂余胜军 QQ644064779 www.mayikt.com * @Version V1.0 **/ @FunctionalInterface public interface YouShenIn...

C#如何获取其他程序ListView控件中的内容

源码下载:http://download.csdn.net/detail/php_fly/4923388 需求:获取其他程序中的ListView控件的文本内容 原理:进程之间是相互隔离的,数据是不能共享的(有些特例)    LVM_GETTITEMTEXT:将一个数据缓冲区提供给listview32控件,你不能把你的进程的数据缓冲提供给另外的程序,所以要用...

Java高并发网络编程(四)Netty

在网络应用开发的过程中,直接使用JDK提供的NIO的API,比较繁琐,而且想要进行性能提升,还需要结合多线程技术。 由于网络编程本身的复杂性,以及JDK API开发的使用难度较高,所以在开源社区中,涌现出来了很多对JDK NIO进行封装、增强的网络编程框架,比如Netty、Mina等。 一、Netty简介 https://netty.io/官网 Netty...

关于OPC自动化接口编程(OPCDAAuto.dll)几点注意问题

为了能够在工作中方便的应用OPC和充分的理解OPC的开发流程、内部机制,这两天正在研究开发OPC客户端程序,一般我们开发OPC客户端程序有以下几种方式: (1)       使用OPCNetAPI,需要用到OPCNetAPI.dll,OPCNetAPI.Com.dll (2)       使用自动化接口,需要用到OPCDAAuto.dll (3)     ...