C++ 标准库之可调用对象

标准库函数对象

算术

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;}}

}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值