标准库函数对象
算术
plus<T>
minus<T>
divides<T>
negate<T>
关系
equal_to<T>
not_equal<T>
greater<T>
greater_equal<T>
less<T>
less_equal<T>
逻辑
logical_and<T>
logical_or<T>
logical_not<T>
lambd表达式生成的函数对象
lambda表达式
[capture list](parameter list)->return type{function body}
是一个函数对象 (是一个没有被命名的 由编译器生成的 类类型的对象)
可以忽略return type和parameter list
lambda表达式的捕获与返回
capture用于捕获当前所在函数作用域的任何局部变量
只有在捕获局部变量后才可以在function body中使用局部变量
捕获方式
值捕获:在lambda创建时拷贝
引用捕获:在function body中使用捕获变量时以引用方式进行
以引用方式捕获局部变量时 要求在lambda执行过程中 引用的变量时始终存在的
隐式捕获:这种情况下 lambda会捕获函数参数列表里的所有局部变量
[=]() {} 默认捕获方式为值
[&](){} 默认捕获方式为引用
如果希望一部分以值,一部分以引用 则有如下形式
[=,&os]其余局部变量默认以值捕获
[&, str ]其余局部变量默认以引用捕获
可变lambda
默认情况下,lambda不会改变一个由值捕获而来的变量,如果我们希望改变,则有如下形式
[v1]()mutable{return ++v1;} 需要添加mutable关键字
对于引用捕获的变量 是否可以改变其值 取决于其引用内容是否是const
指定lambda返回类型
默认情况下 如果一个lambda的function body含有除return 外的其他语句 则return-type为void 如果我们需要返回一个类型的对象 且函数体内不只有一条return语句 则需要return-type
当然你如果作弊: return a>0?a:-a; 那不写返回值类型也是可以的
为什么使用lambda
在于lambda含有捕获列表 一些泛型算法的参数只能是一元谓词 在这个时候传递一个函数不可行,但是lambda就可以捕获所在函数的局部变量 用于运算
标准库bind函数
函数适配器
接受一个可调用对象 生成一个新的可调用对象来适应原对象的参数列表
auto newCallable = bind(callable,arg_list)
bind()会调用callable 并且传递arg_list中的参数给callacle
arg_list参数
auto check6 = bind(check_size,_1,6)
_1是占位符 表示check6的第一个参数对应check_size的第一个参数
有几个占位符 表示check6接受几个参数
且参数位置按照占位符来 _1对应第一个参数 _2对应第二个参数
arg_list会用于调用可调用对象check_size
调用顺序是:
check6(_1)
然后在check6的函数体中
调用check_size(_1,6)
在check6的函数体中调用check_size时
会按照arg_list中的顺序传递参数给check_size
比如 auto g = bind(f,1,2,_2,3,4,_1)
则调用如下 g(_1,_2) g的第一个参数将会被传递给f的第五个参数
f(1,2,_2,3,4,_1) 这也不难理解 因为传递参数的顺序在函数适配时就已经固定
绑定引用参数
使用标准库ref函数
bind(print,os,_1,’ ’);//os时ostream对象 因此只能采用引用形式
bind(print,ref(os),_1,’ ’);
利用标准库函数对象实现函数表(利用map实现string到一个可调用对象的映射)
map<string,int*(int,int)> binops;
不同类型可能具有相同调用形式
int add(int i, int j) { return i + j; }
auto mod = [](int i, int j) {return i % j; };
struct divide { int operator() (int denominator, int divisor) { return denominator / divisor; } };
上述三种可调用对象具有相同的形式
int (int ,int )
但是对于我们构建的函数表 我们不能传递mod和divide作为second传入binops中
(因为类型不匹配)mod 和 divide显然不属于int*(int,int)的函数类型
标准库function类型
为了解决上述问题 function类型出场了
构造
function<T> f; //空function
function<T> f(nullptr); //空function
function<T> f(obj); //含有可调用对象obj副本的function
f //在条件表达式中使用f 如果f含有一个obj则为true反之为false
f(args) //调用f中的对象 参数是args
function<T>的成员的类型
result_type //f的可调用对象返回的类型
argument_type //是类型T的参数类型
first_argument_type //如果仅一种类型 则无差异
second_argument_type //否则一个表示第一个参数类型 一个表示第二个参数类型
用function套bind则可以实现含多个参数类型的Function函数对象
function<int(int,int)> f1 =add;
function<int(int,int)> f2 =divide();
function<int(int,int)> f3 =[](int i,int j){return i*j;}
现在可以重新定义binops
map<string,function<int(int,int)>> binops;
binops={
{“+”,add}
{“-”,std::minus<int>}
{“/”,divide()}
{"*",[](int i,int j){return i*j;}}
}