C++Primer 第10章lambda表达式
泛型编程
咱们继续高歌猛进,下面我给大家继续讲关于算法的故事。
我们知道标准库容器中定义的算法大多数独立在算法之外,通常这些算法是通用的。它们可以处理不同类型的容器中的元素。是不是听起来非常的神奇?不同的容器可以利用相同的算法,这些功劳都可以归因于他们拥有相同的迭代器接口,虽然不同的容器其数据结构不同。但是其迭代器经过包装,给用户在使用时, 可以使用相同的操作方法,来对不同的容器进行操作,那么算法就可以利用迭代器来间接地访问容器内的元素,从而达到处理元素的目的。因此,大多数的算法并不依赖于容器本身,不过某些容器对于某些算法有特定的优化,虽然公用的算法可以实现其目的,但是其效率并不如容器自己定义的算法。
那么这些算法又有哪些功能呢?本书可以将算法归为以下几类:
只读算法,例如 find,accumulate,equal 等算法。
写容器元素的算法,例如 fill,copy,
replace_copy等算法。
重排元素的算法,sort,unique等算法。
删除元素的算法,free,erase等算法。
这些算法的具体操作,我在这里就不一一赘述了。因为我也记不住,哈哈。
lambda表达式
当把书看到这里的时候 我不未免觉得这个东西有点的奇怪,但是当我仔细阅读之后,我突然发现C++11相比于C++98改变是革命性的,这个表达式就清楚地体现了c++11的强大以及灵活之处。
其实我在之前学习qt的时候,在快速定义信号槽时,我有遇见过该表达式,当时我以为这样的语法是qt内自带的,与C++没有关系。中括号内传入的引用以及等于号,这样的操作,真的非常的绝妙,回想我之前编写的一些程序,用到该表达式,真的会让代码更加的清爽且易于实现。那么言归正传,什么是lambda表达式呢?这种表达式其实是一种函数的变体。都有返回类型,函数体以及参数列表,但是与普通的函数不同。lambda表达式没有名称,并且在之前的中括号内可以传入更多的参数,并且更加灵活以及清爽,以下是lambda表达式的写法:
[传入的已有的参数](参数列表)这里可以显式的定义return类型
{
函数体
return(不写表达式函数为void类型)
}
首先说中括号
我们先从这个中括号开始说起,中括号学名捕获列表,在中括号内可以写入一些变量或者引用,这样可以使lambda表达式函数体之中,使用到变量的引用与拷贝,值得注意的是,传入的引用以及变量,是之前程序中必须要初始化定义的,否则会使该处出错。
当然 中括号内也可以隐式的传入一些数据,中括号内写 = 时,编译器将运行至该处,已经定义的元素,统一的拷贝入lambda表达式中,在表达式的函数体中使用这些元素时,使用的是该元素的拷贝,点值得注意。
当中括号中写 & 时,编译器将运行至此处,已经定义的元素的地址传入lambda表达式中,表达式函数题当中改变元素的时候,表达式之外元素的内容也会发生改变。
本书中建议,中括号内传入的变量需要尽量简单,因为当我们捕获一个指针或者迭代器时,在表达式中,一定需要关注,传入时也要有预期的值。一般来说,我们应该尽量减少捕获的数据量,来避免潜在的捕获导致的问题,并且应该尽可能不捕获指针或者引用。
说说小括号
小括号中与普通的函数体相同,都是参数列表,这里的使用方法与普通的函数相同。不做更多的描述。
说说大括号
便是lambda表达式的函数体,lambda表达式的函数体,与普通的函数使用方法一致,不过我们发现,表达式的写法并没有定义返回类型,这样表达式内需要返回出类型,则就需要一定的考究,当我们不写return时,lambda表达式默认返回void类型,当返回的表达式是变量时,则该表达式返回的类型与该变量相同,类似于auto的使用方法。但是当函数体中返回的类型模棱两可时,表达式就会出现错误,例如 if else 两个不同的块之间,定义了相同的return,但是lambda表达式会报错,这时就需要表达式小括号之后,写 -> 之后跟类型名,来显示的指出return类型。
lambda表达式,也可以当做谓词使用在容器的算法当中,lambda表达式的出现给容积的算法增加了更多的灵活性,让用户更加容易的自定义算法的实现方法,从而降低用户的编写难度。