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::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用来获取调用函数地返回值类型。
#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;
}