如果一个对象或表达式可以使用调用运算符(()
),则可以称它为可调用对象。
可调用对象共有四种:
可调用对象用途很广,包括在调用泛型算法函数(sort(),find_if()等)时,可以传入可调用对象,来指明泛型算法要对指定范围内的元素进行哪种操作。
再来看一下谓词的概念。
谓词是一个可调用的表达式,其返回结果是一个能用作条件的值。标准库算法所使用的的谓词分两类:
一般来说,可调用对象在泛型算法中都被用作谓词传入函数。可以说谓词是可调用对象的一种,也可以说可调用对象可以当做谓词。
介绍lambda表达式之前,最后再引入一个概念:尾置返回类型。
C++11 中尾置返回类型用来简化函数声明,以一个跟在形参列表后面的 ->
开头,函数名前需要用 auto
来表明该函数的返回类型是用尾置返回类型表示的。
尾置返回类型尤其对于返回类型比较复杂的函数最有效,比如数组的指针或数组的引用:
//返回整型数组指针的函数,形参为一个int。
int (*func(int i))[10];
//使用类型别名
auto func(int i) -> int (*)[10];
这样看来使用类型别名声明复杂函数就更简洁明了吧。
终于到它了——lambda表达式。
lambda表达式又称匿名函数,可以把他理解为未命名的内联函数。它必须使用尾置返回类型来定义,其定义形式为:
[capture list] (parameter list) -> return type {function body}
各部分解释:
capture list:是 lambda 所在函数中定义的局部变量的列表(一般不用);
return type:返回类型;
parameter list:参数列表;
function body:函数体。
lambda表达式中可以忽略参数列表和返回类型,忽略参数列表相当于空参数列表,忽略返回类型可以从 return 语句中推断出返回类型:
例子:
auto f = [] {return 0;};
auto f = [] () -> int {return 0;}; //等价定义
cout << f() << endl;
这里定义了一个可调用对象 f,不接受参数,返回 0。
与普通函数一样 lambda 的形参使用实参初始化。实参和形参的类型必须匹配,而且不能有默认参数。
例一:
bool is_shorter(const string &s1, const string &s2){
return s1.size()<s2.size();
}
sort(words.begin(), words.end(), is_shorter);
sort(words.begin(), words.end(), [](const string &a, const string &b)
{return a.size() < b.size();});//等价定义
接受二元谓词的 sort
用传入的谓词替代 <
操作。
第一个 sort 中把 is_shorter 函数作为二元谓词传入,将 vector
第二个把 lambda 表达式作为二元谓词传入,与上一个等价。
例二:
bool is_large(const string &s, string::size_type sz){
return s.size() > sz;
}
auto iter = find_if(words.begin(), words.end(), is_large);
auto iter = find_if(words.begin(), words.end(),
[](const string &s, string::size_type sz){return s.size() > sz;})
这段代码看似是返回 vector
别着急,利用capture list可以解决传入多个参数的问题。
当 lambda 表达式出现在函数中,就可以使用函数中的局部变量,我们需要通过 capture list 指出将会使用的变量。
这样我们就可以直接使用局部变量 sz,而不用通过传参使用它了:
string::size_type sz = 5;
auto iter = find_if(words.begin(), words.end(),
[sz](const string &s, string::size_type sz){return s.size() > sz;})
🎉到此 lambda 表达式的讲解就结束了,从今天开始更新 C++ 的基础知识,后面应该会讲解一下标准容器,并手动实现。
希望大家多多关注,三连支持。你们的支持是我源源不断创作的动力。