淘宝客网站建设多少钱,青海省住房和建设门户网站,淘宝客做的好的几个网站,wap网站怎么做一、lambda表达式
1#xff09;、为啥需要引入lambda#xff1f; 在c98中#xff0c;我们使用sort对一段自定义类型进行排序的时候#xff0c;每次都需要传一个仿函数#xff0c;即手写一个完整的类。甚至有时需要同时实现排升序和降序#xff0c;就需要各自手写一个类、为啥需要引入lambda 在c98中我们使用sort对一段自定义类型进行排序的时候每次都需要传一个仿函数即手写一个完整的类。甚至有时需要同时实现排升序和降序就需要各自手写一个类非常不方便所以C11引入了lambda表达式 lamaba是一个匿名函数对象是一个可调用对象表达式本质上也是一个类vs中类名为lambda_uuid,并实现了operator()。
【C98玩法】
struct Goods
{string _name; // 名字double _price; // 价格int _evaluate; // 评价Goods(const char* str, double price, int evaluate):_name(str), _price(price), _evaluate(evaluate){}
};
struct ComparePriceLess
{bool operator()(const Goods gl, const Goods gr){return gl._price gr._price;}
};
struct ComparePriceGreater
{bool operator()(const Goods gl, const Goods gr){return gl._price gr._price;}
};
int main()
{vectorGoods v { { 苹果, 2.1, 5 }, { 香蕉, 3, 4 }, { 橙子, 2.2, 3 }, { 菠萝, 1.5, 4 } };sort(v.begin(), v.end(), ComparePriceLess());sort(v.begin(), v.end(), ComparePriceGreater());
}【C11 lambda表达式】
int main()
{vectorGoods v { { 苹果, 2.1, 5 }, { 香蕉, 3, 4 }, { 橙子, 2.2, 3 }, { 菠萝, 1.5, 4 } };sort(v.begin(), v.end(), [](const Goods g1, const Goods g2) {return g1._price g2._price; });sort(v.begin(), v.end(), [](const Goods g1, const Goods g2) {return g1._price g2._price; });sort(v.begin(), v.end(), [](const Goods g1, const Goods g2) {return g1._evaluate g2._evaluate; });sort(v.begin(), v.end(), [](const Goods g1, const Goods g2) {return g1._evaluate g2._evaluate; });
}2、lambda表达式语法 lambda表达式书写格式[capture-list] (parameters) mutable - return-type { statement }
capture-list捕捉列表编译器根据[ ]来判断接下来的代码是否为lambda函数[ ]可以捕捉父作用域的变量供lambda函数使用。parameters列表参数和普通函数列表参数一样。如果没用可以连同()一起省略。mutable 默认情况下lambda是一个const函数实际上是用于修饰operator()的mutable可以取消其常量性。使用该修饰符时参数列表不可省略(即使参数为空)。return-type用于声明返回值类型。如果没用返回值可以省略即使有返回值也可以省略由编译器自动推导statement 函数体。在该函数体内除了可以使用其参数外还可以使用所有捕获到的变量。 在lambda函数定义中参数列表和返回值类型都是可选部分而捕捉列表和函数体可以为空。因此C11中最简单的lambda函数为[]{}; 该lambda函数不能做任何事情。
3、capture-list捕捉列表细节 捕捉列表用于捕捉父作用域中变量供lambda函数使用捕捉方分为以下几种
[var]表示值传递方式捕捉变量var。[]表示传值方式捕捉父作用域中的所有变量(包括this)。[var]表示引用传递方式捕捉变量var。[]表示引用方式捕捉父作用域中的所有变量(包括this)。[this]表示值传递方式捕捉当前的this指针 除此之外捕捉列表可以由多个捕捉项组成以逗号分割。比如 [, a, b]:除引用捕捉a、b外其他父作用域变量传值捕捉 [, a, this]:值传递方式捕捉变量a和this引用方式捕捉其他变量。 并且捕捉列表不能重复变量传递否则会导致编译错误。比如[, a]:a变量传递了两次。lambda表达式之间不能相互赋值即使类型相同但编译后类名都变为了lambda_uuid类名不相同
4、函数对象与lambda表达式 函数对象又称仿函数既可以像普通函数一样使用在类中重载operator()。而lambda本质上一个一个函数对象在编译后会转化成一个仿函数并对operator()进行重载
class Rate
{
public:Rate(double rate) : _rate(rate){}double operator()(double money, int year){return money * _rate * year;}
private:double _rate;
};int main()
{// 函数对象double rate 0.49;Rate r1(rate);r1(10000, 2);// lamberauto r2 [](double monty, int year)-double {return monty * rate * year;};r2(10000, 2);return 0;
}【反汇编结果】
二、function包装器
1、包装器由来 function包装器 也叫作适配器包装的是可调用对象。C中的function本质是一个类模板也是一个包装器。 在C中有3种可调用对象函数指针、仿函数、lambda但我们发现想要获得他们的都存在一些缺陷函数指针非常麻烦类型和对象嵌在一起仿函数很重即使是一个很简单的比较逻辑也要在外面定义一个类lambda没法写类型不同的机器和时间uuid不同并且相对匿名当然decltype可以获的 除此在外众多的可调用对象类型会导致模板的效率低下! 原因在于假设现在存在一个函数模板我需要将一个可调用对象作为模板参数进行传递来达到某种目的。但众多的可调用对象可能实现的是同一个功能但分别传递给模板后需要实例化3份导致模板效率降低所以包装器对可调用对象进行了统一
【实例】
templateclass F, class T
T useF(F f, T x)
{static int count 0;cout count: count endl;cout count: count endl;return f(x);
}
double f(double i)
{return i / 2;
}
struct Functor
{double operator()(double d){return d / 3;}
};
int main()
{ // 函数名cout useF(f, 11.11) endl;// 函数对象cout useF(Functor(), 11.11) endl;// lamber表达式cout useF([](double d){ return d / 4; }, 11.11) endl;return 0;
}
2)、包装器原型
std::function在头文件functional
// 类模板原型如下
template class T function; // undefined
template class Ret, class... Args
class functionRet(Args...);
模板参数说明
Ret: 被调用函数的返回类型
Args…被调用函数的形参即现在存在一个包装器为functionint(int, int)该包装器将所有的参数为2个int返回值为int的所有可调用对象进行统一认为是一个类型
3)、使用
templateclass F, class T
T useF(F f, T x)
{static int count 0;cout count: count endl;cout count: count endl;return f(x);
}
double f(double i)
{return i / 2;
}
struct Functor
{double operator()(double d){return d / 3;}
};int main()
{// 函数名std::functiondouble(double) func1 f;cout useF(func1, 11.11) endl;// 函数对象std::functiondouble(double) func2 Functor();cout useF(func2, 11.11) endl;// lamber表达式std::functiondouble(double) func3 [](double d){return d;};cout useF(func3, 11.11) endl;return 0;
}4、面试题
150. 逆波兰表达式求值
class Solution {
public:int evalRPN(vectorstring tokens) {unordered_mapstring, functionint(int, int) ophash {{, [](int x, int y){return x y;}},{-, [](int x, int y){return x - y;}},{*, [](int x, int y){return x * y;}},{/, [](int x, int y){return x / y;}}};stackint st;for(auto str : tokens){if(ophash .find(str) ! ophash .end()){int right st.top(); st.pop();int left st.top(); st.pop();st.push(ophash [str](left, right));}elsest.push(stoi(str));}return st.top();}
};三、bind绑定 bind也是一个函数模板可以接收一个可调用对象并返回一个新的可调用对象用于调整参数的个数和顺序
// 原型如下
template class Fn, class... Args
/* unspecified */ bind (Fn fn, Args... args);
// with return type (2)
template class Ret, class Fn, class... Args
/* unspecified */ bind (Fn fn, Args... args);调用bind的一般形式auto newCallable bind(callable,arg_list);其中newCallable本身是一个可调用对象arg_list是一个逗号分隔的参数列表对应给定的callable的参数。当我们调用newCallable时newCallable会调用callable,并传给它arg_list中的参数。 arg_list中的参数可能包含形如_n的名字其中n是一个整数这些参数是“占位符”表示newCallable的参数它们占据了传递给newCallable的参数的“位置”。数值n表示生成的可调用对象中参数的位置_1为newCallable的第一个参数_2为第二个参数以此类推。
1普通绑定用法
【实例】
int Sub(int a, int b)
{return a - b;
}int main()
{std::functionint(int, int) func1 std::bind(Plus, std::placeholders::_1, std::placeholders::_2);std::cout func1(10, 2) std::endl;
}bind函数中_1和_2都是占位符。当执行func1(10, 2)函数时参数10和2会被作为参数传递给Plus函数。其中std::placeholders::_1表示func1第一个参数的位置 std::placeholders::_2表示第二个参数所在位置 2、改变参数位置 既然_1和_2是占位符所以仅需改变两者位置所以func函数传递给Plus的参数即可转换。具体结果如下
int Sub(int a, int b)
{return a - b;
}int main()
{std::functionint(int, int) func1 std::bind(Sub, std::placeholders::_2, std::placeholders::_1);std::cout func1(10, 2) std::endl;
}3改变参数的个数 我们在类外调用一个类成员函数调用成员函数时第一个参数为该对象的指针。但每次我们手动传递的时候非常麻烦。所以我们可以通过bind()将第一个参数进行绑死改变参数个数。具体如下
class Plus
{
public:static int Plusi(int x, int y){return x y;}double Plusd(double x, double y){return x y;}
};
int main()
{Plus ps;// 正常情况下第一个参数this指针需要手动传递 麻烦std::functiondouble(Plus*, double, double) func1 Plus::Plusd;std::cout func1(ps, 10.1, 20.2) std::endl;// 将第一个参数绑死为Plus* std::functiondouble(double, double) func2 std::bind(Plus::Plusd,ps, std::placeholders::_1, std::placeholders::_2);std::cout func2(10.1, 20.2) std::endl;// 将第一个参数和第三个参数绑死std::functiondouble(double) func3 std::bind(Plus::Plusd, ps, std::placeholders::_1, 1.1);std::cout func3(10.1) std::endl;// 所有参数直接全部绑死 注意此处博主绑定的是静态函数auto func4 std::bind(Plus::Plusi, 10, 10);std::cout func4() std::endl;//绑定时第一个参数因为指针但编译器做了特殊处理可以绑定临时对象std::functiondouble(double, double) func5 std::bind(Plus::Plusd, Plus(), std::placeholders::_1, std::placeholders::_2);std::cout func5(1.1, 2.2) std::endl;
}