前言
在 C++11 标准带来的诸多革命性特性中,'简化代码编写'与'统一可调用对象管理'是两大核心目标。lambda 表达式解决了传统仿函数'定义繁琐、复用性低'的痛点,让局部场景下的自定义逻辑(如排序规则、回调函数)能以更简洁的匿名函数形式实现;可变参数模板则打破了模板参数数量固定的限制,为 STL 容器(如 emplace_back)和通用函数设计提供了灵活的参数处理能力;而 function 包装器与 bind 函数,则进一步整合了函数指针、仿函数、lambda 等不同类型的可调用对象,实现了统一管理与参数适配,甚至让可调用对象存储到容器中成为可能。
这些特性并非孤立存在——lambda 的底层依赖仿函数实现,可变参数模板为 emplace 系列接口提供了技术支撑,function 与 bind 则基于前两者的特性,解决了'不同可调用对象类型不统一'的问题。本文将从实际开发需求出发,先讲解 lambda 表达式的语法规则与捕获逻辑,再深入可变参数模板的展开方法与应用场景,最后通过 function 包装器与 bind 函数的实例,展示如何统一管理各类可调用对象、灵活调整参数顺序与固定参数值。
文中不仅会拆解易混淆的概念(如 lambda 的 mutable 修饰符作用、placeholders 占位符的使用规则),还会结合具体代码示例(如用 vector 存储 function 对象、用 bind 适配类成员函数),帮助读者理解这些特性的设计逻辑与实际价值。同时,文末的作业解析也将围绕 C++11 常见考点(如范围 for 的适用场景)展开,进一步巩固对标准特性的理解,为后续高效使用 C++11 进行开发打下基础。
lambda 表达式
lambda 表达式是局部的匿名的函数对象,所以 sort 填仿函数那里可以写这个。底层其实是用的仿函数实现的。
该表达式不存在重载的说法。引申:auto f1 = []{}; 和 auto f2 = []{}; f1 和 f2 也不是同一类型,f1=f2 的话会报错。也就是 lambda 表达式之间不能相互赋值,即使看起来类型相同。
[捕捉列表](参数列表)(mutable)-> 返回值类型 { 函数体 };
捕获列表的话可以捕获这个表达式所在域的局部变量,函数也可以捕捉,全局域里的不用捕获也能用。这种的强行捕获可能会报错。参数列表里面不传参的话,() 也可以省了。这个 mutable 的话可以取消捕获列表里面东西默认的 const 性,但是在用该修饰符的时候,参数列表不能省略。如果捕获的东西本来是 const 的话,加了 mutable 也变不了。注意:捕获列表默认是 const 的。返回值类型一般可以不用写,编译器会推导。
捕获列表说明
[var]:表示值传递方式捕捉变量 var,var 的类型会跟传递过来的一模一样。[=]:表示值传递方式捕获所有父作用域中的变量 (包括 this)。[&var]:表示引用传递捕捉变量 var。[&]:表示引用传递捕捉所有父作用域中的变量 (包括 this)。
这里的 & 和 =:如果是 [&, x] 那就只有 x 是值传递,其他都是引用。注意:捕捉列表不允许变量重复传递,否则就会导致编译错误,例如 [=, a] 就不行,a 捕获了两次。
用法展示
引申:可调用对象的四个存储方法:函数指针、仿函数、lambda 表达式、用包装器搞到容器里面。
可变参数模板
就是让模板参数可以是不确定的数目。其实日常自己写的话很少用的。
template<class... Args>
void ShowList(Args... args) {}
Args 表示一个包含零个或多个类型的参数包,args 也是参数包,里面可以是 0 或多个参数。... 是展开参数包的操作(放在参数包后面,除了模板参数声明那里)。但是这个参数包想知道里面的参数是啥的话比较困难,不支持 eg: arg[1] 这样。
展开参数包的方法
- 递归展开参数包
- 逗号表达式展开参数包


