lambda
表达式¶
该笔记基于课程CS106L的学习,用于记录一些cpp的重要特性以及先前不曾了解的cpp特性。
定义¶
在Python中,lambda
表达式函数式编程中起到了极大的简化作用。自C++11起,C++也引入了lambda
表达式,增强了C++的函数式编程能力。
lambda
表达式是一种匿名函数对象,可在需要在需要函数功能的地方直接定义和使用,而无需单独定义一个函数。
lambda
表达式是内联的、匿名的函数,能够知晓于其处于相同作用域的变量。
auto var = [capture-clause] (auto param) -> return_type { /* function_body */ }
/* ^ ^ */
/* outside parameters func parameters */
e.g.:
int limit = 5;
auto lessThanFive = [limit] (int n) {
return n < limit;
};
lessThanFive(6); // False
捕获列表([capture-clause]
)¶
[] // captures nothing
[limit] // captures limit by value
[&limit] // captures limit by reference
[&limit, upper] // captures limit by reference, upper by value
[&, limit] // captures everything except limit by reference
[&] // captures everything by reference
[=] // captures everything by value
应用 & 杂项¶
lambda
表达式的计算成本很低,可提高程序的运行效率。
需要一个简短的函数或需要在函数中访问局部变量时,可使用
lambda
表达式若需要使用更复杂的逻辑或重载功能,可使用函数指针
函数指针
-
和其他指针共享操作接口,即可像其他指针一样进行处理
-
可作为变量/参数在函数或模板函数中传递
-
可像函数一样被调用
lambda
表达式作为谓词传递¶
template<typename InputIt, typename UniPred>
int count_occurrences(InputIt begin, InputIt end, UniPred pred) {
int count = 0;
for (auto iter = begin; iter != end; ++iter) {
if (pred(*iter)) { count++; }
}
return count;
}
int main() {
int limit = 5;
auto moreThanFive = [limit] (int n) {
return n > limit;
}
std::vector<int> nums = {3, 5, 7, 9, 11, 13};
count_occurrences(nums.begin(), nums.end(), moreThanFive) // returns 4
}
在上面的示例中,InputIt
是输入的迭代器类型;UniPred
是一个一元谓词类型(函数指针/函数对象/Lambda表达式),用于判断元素是否满足条件。
模板函数count_occurrences
的功能是遍历从begin
到end
的所有元素;对每个元素,调用pred
谓词判断是否满足条件,如果满足条件,计数器 count 增加;最后返回计数器的值。
谓词函数(Predicate Functions)
-
任何返回
bool
值的函数都属于谓词函数 -
谓词函数可以是一元或多元的,即单参数的或多参数的
函数对象/函子(Function Object/Functor)¶
在函数式编程中,这是一个十分重要的模块。
在C++中,函数对象和函子是同一个概念,指通过重载了operator()
运算符的类实现的技术。这项技术使得该类能够创建用户自定义功能的闭包,其实例能够像函数一样使用,从而提供更加灵活的函数式编程方式。
闭包(Closure)
函数对象的单一实例化形式,能够捕获并保持对其所在作用域中变量的引用,即使该作用域已经执行完毕。可简单理解为一个会记住其周围环境(词法作用域)并访问其中变量的函数,即使这个函数在这个环境外调用。
在C++中,闭包通常就通过lambda
表达式实现。
class factor {
public:
int operator() (int arg) const {
return num + arg; // parameters and function body
}
private:
int num; // capture clause
};
int num = 0;
auto lambda = [&num] (int arg) {
num += ara;
};
lambda(5);
-
factor
是一个函数对象,对于捕获变量num
,由于其是factor
的私有变量,是不可变的,故这个函数对象仅仅提供了一个只读的加法操作 -
lambda
表达式则通过引用捕获提供了一个可以修改捕获变量的操作,即对捕获变量num
的累加。这就是一个典型的闭包
std::function<return_type(param_types)> func;
¶
到目前为止,我们已经讨论了lambda
表达式、函数指针以及函数对象。
在C++中,STL提供了一个通用的函数类型std::function<return_type(param_types)>
,称为标准函数。以上讨论的三个东西都可以转换为标准函数。
标准函数占用的资源会比函数指针与lambda
表达式多,运行开销也更大。