2、函数指针。和数组名一样,函数名即为函数指针。
void fff(int x){ //被调用的函数 cout<<x<<endl; } void fcn(void (*fp)(int ),int x){ //形参为函数指针 fp(x); } typedef void (*Ftype)(int ); //定义一个函数指针类型Ftype void fcn0(Ftype fp,int x){ fp(x); } int main(){ fcn(fff,100); //函数fcn调用函数fff fcn0(fff,200); //函数fcn0调用函数fff }3、lambda表达式。lambda表达式就是一段可调用的代码。主要适合于只用到一两次的简短代码段。由于lambda是匿名的,所以保证了其不会被不安全的访问。lambda表达式的形式如下:
void fcn1(){ size_t v1=42; auto f=[v1]{ return v1;};//创建lambda表达式,如果参数列表为空,可以省去() v1=0;//改变v1的值 auto j=f(); //调用lambda表达式,j的值为42 }如果执行体内只有单一的return语句,那么lambda表达式可以不指明返回类型,但如果执行体内还有其他语句,那么lambda语句必须指明返回类型,并且返回类型必须尾置。
另外,lambda的捕获列表在一定程度上弥补了标准库中某些算法在使用谓词上的不便。例如标准库中find_if算法的第三个参数接收一个一元谓词,因此传递给find_if的可调用对象必须接收单一参数。现在有这样一个任务,words是一个存放了若干单词的vector<string>对象,现在要从中找出长度大于指定长度sz的第一个单词。见以下代码:
bool check(const string &a,string::size_type st){ return a.size()>=st; } vector<string>::iterator first(const vector<string> &words,string::size_type st){ auto wc=find_if(words.begin(),words.end(),check); //错误,check是二元谓词 auto wc=find_if(words.begin(),words.end(),[st](const string &a){ return a.size()>=st });//正确,这里的lambda表达式是一元谓词,只传递了一个参数 return wc; }
class 无名{ public: bool operator()(const string &a) const { return a.size()>=st; } private: string::size_type st; }无名类中的函数调用运算符默认是const的,因此lambda表达式默认是不能对捕获列表中捕获的变量进行修改的,如果想修改,必须在lambda表达式的参数列表之后和执行体之前加上mutable关键字。见下例:
void fcn(){ int v=100; auto f=[v](){ return ++v; }//错误,不能修改v auto f=[v]()mutable { return ++v; }//正确,可以修改v v=0; int j=f();//j为101 }
4、bind函数。定义在头文件functional中,可以将bind函数看做一个通用的函数适配器,它生产一个可调用对象来“适应”原对象的参数列表。bind的一般调用形式如下:
auto newCallable = bind( callable,arg_list )
newCallable是由bind生成的新的可调用对象,callable是原对象,arg_list参数列表对应了原对象的参数列表。
例如对于之前的find_if的第三个参数,我们也可以用bind函数来书写:
auto wc=find_if(words.begin(),words.end(),bind(check,_1,st));说明:_1是占位符,表明新生产的可调用对象的第一个参数对应了原对象check的第一个参数。st作为check的第二个参数。对于与句:auto g = bind(f,a,b,_2,c,_1);bind将函数g(_1,_2)映射为f(a,b,_2,c,_1)。
5、函数对象。重载了函数调用运算符的类的对象即为函数对象。