如何建立自己网站视频,有效获客的六大渠道,网站上搜索的动图怎么做壁纸,个人注册入口官网C——C11#xff08;3#xff09; lambda表达式#xff08;匿名的仿函数对象#xff09;一些注意点lambda捕捉列表[][][this] lambda的赋值 function包装器function成员函数的包装 bind绑定参数 我们今天接着来了解一下C11一些新的特性#xff0c;如果还没有看过上两… C——C113 lambda表达式匿名的仿函数对象一些注意点lambda捕捉列表[][][this] lambda的赋值 function包装器function成员函数的包装 bind绑定参数 我们今天接着来了解一下C11一些新的特性如果还没有看过上两次的小伙伴可以点击这里 https://blog.csdn.net/qq_67693066/article/details/136577386 https://blog.csdn.net/qq_67693066/article/details/136658325 lambda表达式匿名的仿函数对象
后期C受到了其他语言的影响风格开始发生了变化这个lambda表达式就是受了其他语言的影响 在C中lambda表达式也称为匿名函数提供了一种方便的方式来定义和使用内联的小函数对象。Lambda表达式特别适用于需要临时函数对象的情况例如在算法调用如std::sort、std::find_if等中作为参数传递。 C中的lambda表达式的基本语法如下
[capture](parameters) - return_type { body_of_lambda }capture捕获子句用于捕获外部作用域的变量以在lambda函数体内使用。可以是值捕获通过或引用捕获通过。也可以显式列出要捕获的变量。 parameterslambda函数的参数列表与常规函数参数列表类似。 return_type返回类型通常可以省略编译器会自动推导返回类型。 body_of_lambdalambda函数的主体包含要执行的代码。 注意 在lambda函数定义中参数列表和返回值类型都是可选部分而捕捉列表和函数体可以为空。因此C11中最简单的lambda函数为[]{}; 该lambda函数不能做任何事情。 比如我可以用lambda表达式写一个简单的判断偶数的式子
int main()
{vectorint v1 {1,2,3,4,5,6,7,8,9,10};auto s1 [v1](int n){ //捕捉v1参数为nif( n % 2 0){coutn是偶数endl; //body_of_lambda}};for(auto e : v1){s1(e); //调用s1}
}我们可以看看s1的类型
cout typeid(s1).name() endl;这里class lambda_741bc9d219826239a4505f712752848a后面的这串字符串是uuid通用唯一识别码然后编译器会生成这么一个类型的仿函数
我们打个断点进入到反汇编 我们可以通过lambda表达式实现自定义排序 之前在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() {vector Goods v {{苹果, 2.1, 5},{香蕉, 3,4},{橙子, 2.2,3},{菠萝, 1.5, 4}};sort(v.begin(), v.end(), ComparePriceGreater()); //使用ComparePriceGreater()匿名对象for(auto e: v){coute._name : e._price endl;}sort(v.begin(), v.end(), ComparePriceLess());cout endl;for (auto e : v){cout e._name : e._price endl;}
}
现在我们有lambda匿名仿函数对象我们就可以不用写这么多的仿函数了 sort(v.begin(), v.end(), [](const Goods g1, const Goods g2){return g1._price g2._price; });for (auto e : v){cout e._name : e._price endl;}sort(v.begin(), v.end(), [](const Goods g1, const Goods g2){return g1._price g2._price; }); cout endl;for (auto e : v){cout e._name : e._price endl;}
}一些注意点
既然我们可以通过lambda实现一些仿函数的功能那么我们可以用这个实现一个简单的交换两个变量值的功能
int main()
{int x 10;int y 19;cout x y endl;//使用lambda表达式auto s1 [x, y]() {int temp;temp x;x y;y temp;};但是这样会报错 那是因为默认情况下lambda函数总是一个const函数mutable可以取消其常量性。使用该修饰符时参数列表不可省略(即使参数为空)。 这下就可以了
int main()
{int x 10;int y 19;cout x y endl;//使用lambda表达式auto s1 [x, y]() mutable{int temp;temp x;x y;y temp;};cout endl;s1();cout x y endl;
}这里我们的s1没有传参是因为捕获列表[]捕捉到了上面的xy{}函数体直接使用的是x和y
我们来运行一下 发现这里并没有实现交换估计多半是传的临时对象我们可以传引用 不仅这样lambda的捕捉列表给了几种方式
lambda捕捉列表 [var]表示值传递方式捕捉变量var []表示值传递方式捕获所有父作用域中的变量(包括this) [var]表示引用传递捕捉变量var []表示引用传递捕捉所有父作用域中的变量(包括this) [this]表示值传递方式捕捉当前的this指针 我们来看看[]和[][this]的玩法
[] []表示值传递方式捕获所有父作用域中的变量(包括this) int main()
{int x 10;int y 90;//lambda表达式 x属于外部变量auto lambda []()mutable {x 90;y 90;cout x y endl;};lambda();cout endl;//查看数值是否被修改cout x y endl;
}发现原本的数值没有改变。
[]
[]表示值传递方式捕获所有父作用域中的变量(包括this)
int main()
{int x 10;int y 90;//lambda表达式 x属于外部变量auto lambda []() {x 90;y 90;cout x y endl;};lambda();cout endl;//查看数值是否被修改cout x y endl;
}[this]
[this]表示值传递方式捕捉当前的this指针
class MyClass {
public:int value;MyClass(int v) : value(v) {}void printValuePlusTen() {// 使用 [this] 捕获当前对象的 this 指针 auto lambda [this]() {std::cout this-value 10 std::endl;};lambda(); // 输出 value 的值加 10 }
};int main()
{MyClass obj(5);obj.printValuePlusTen(); // 输出: 15 cout obj.value endl; //输出5return 0;
}需要注意的是由于this指针是通过值传递的因此lambda内部对this指针的拷贝进行操作时不会影响到原始的this指针或对象本身。
除了这样还可以混合使用 语法上捕捉列表可由多个捕捉项组成并以逗号分割。 比如[, a, b]以引用传递的方式捕捉变量a和b值传递方式捕捉其他所有变量 [a, this]值传递方式捕捉变量a和this引用方式捕捉其他变量 lambda的赋值
注意一下就算两个lambda函数的捕获列表参数函数体都是一样的这两个lambda本质上类型不一样无法互相赋值
int main()
{int x 10;int y 19;cout x y endl;//使用lambda表达式auto s1 [x, y](){int temp;temp x;x y;y temp;};auto s2 [x, y]() {int temp;temp x;x y;y temp;};s1 s2;}会报错
function包装器
现在我们学习了lambda现在我们调用一个函数有多种方法了 函数指针仿函数lambda这有时候方法多了用法就会混有没有什么方法可以将他们统一起来呢
C11中引入了function function 是 C 标准库 头文件中定义的一个模板类它包装了任何可调用的目标函数、lambda 表达式、函数对象等允许你以一种统一的方式来存储和调用它们。std::function 的一个关键特性是其类型擦除type erasure能力这意味着你可以使用同一个 std::function 对象来存储不同类型的可调用对象只要它们具有兼容的调用签名。 举个例子
//函数指针
void Swap_fuc(int r1, int r2)
{int temp r1;r1 r2;r2 temp;
}//仿函数
struct Swap
{void operator()(int r1,int r2){int temp r1;r1 r2;r2 temp;}
};int main()
{//lambda表达式auto s1 [](int r1, int r2) {int temp r1;r1 r2;r2 temp;};
}function可以将这三个很好的结合起来
#includefunctional
//函数指针
void Swap_fuc(int r1, int r2)
{int temp r1;r1 r2;r2 temp;
}//仿函数
struct Swap
{void operator()(int r1,int r2){int temp r1;r1 r2;r2 temp;}
};int main()
{//lambda表达式auto s1 [](int r1, int r2) {int temp r1;r1 r2;r2 temp;};functionvoid(int, int) funtion1;//接收函数指针int r1 10;int r2 90;cout Swap_fuc交换之前的值 endl;cout r1 r2 endl;funtion1 Swap_fuc;funtion1(r1,r2);cout 交换之后的值 endl;cout r1 r2 endl;cout endl;//仿函数cout Swap()交换之前的值 endl;cout r1 r2 endl;funtion1 Swap();funtion1(r1, r2);cout 交换之后的值 endl;cout r1 r2 endl;cout endl;//lambdacout lambda交换之前的值 endl;cout r1 r2 endl;funtion1 s1;funtion1(r1, r2);cout 交换之后的值 endl;cout r1 r2 endl;cout endl;}function成员函数的包装
这里注意一下function对成员函数的包装要加上****
class MyClass
{
public:void func_1(int r1){cout func_1 r1 endl;}void func_2(int r2){cout func_2 r2 endl;}
};int main()
{functionvoid(int) s MyClass::func_1;
}但是会报错 这个错误信息好像说类型好像不一样好像有一个this指针我们得加上 这个时候调用这个函数就会稍微复杂一点 如果嫌弃这样还是过于麻烦我们可以传对象 这样还是太过于复杂有没有什么办法呢有的我们有bind
bind绑定参数 std::bind是C标准库中的一个功能它用于将可调用对象如函数、函数对象或lambda表达式与参数绑定在一起生成一个新的可调用对象。对于成员函数std::bind特别有用因为它允许你指定一个对象实例来调用该成员函数。 举一个简单的例子
void Swap(int r1, int r2)
{int temp r1;r1 r2;r2 temp;
}int main()
{//functionvoid(MyClass,int) s MyClass::func_1;//int u 90;//s(MyClass(), u); //传一个匿名对象auto NewSwap bind(Swap, 20, placeholders::_1);int x 89;NewSwap(x);cout x endl;
}这里我指定函数是Swap绑定了第一个参数为20之后placeholders::_1(_2, _3)表示要传的第一个参数之后会用新绑定的NewSwap这个对象来调用 我们可以利用这一点来简化代码
class MyClass
{
public:void func_1(int r1){cout func_1 r1 endl;}void func_2(int r2){cout func_2 r2 endl;}
};
int main()
{//functionvoid(MyClass,int) s MyClass::func_1;//int u 90;//s(MyClass(), u); //传一个匿名对象//auto NewSwap bind(Swap, 20, placeholders::_1);//int x 89;//NewSwap(x);//cout x endl;functionvoid(int) s bind(MyClass::func_1,MyClass(), placeholders::_1);int x 89;s(x);
}