1. lambda表达式
(1)本质:实际是匿名函数,能够捕获一定范围的变量,与普通函数不同,可以在函数内部定义;
(2)作用:①简化程序结构,因为优化了函数命名与函数传参;②提高程序运行效率,因为优化了函数调用、函数返回等消耗; 适用于简单功能的函数优化;
(3)捕获总结与示例:
① = :按值捕获,只可用不可改
② & :按地址捕获,即可用又可改
③ 变量名:按值捕获,可用不可改
④ &变量名:引用捕获,可用可改
⑤ 副本捕获:c++14后可以自定义变量名 = 捕获变量,但是无法通过副本名改变变量名,示例如下:
#include
using namespace std;
int main(int argc, char **argv)
{
int num1 = 5;
int num2 = 6;
auto func_add = [&num1,num2]() //num1可修改,num2不可修改
{
num1 = 7;
return num1 + num2;
};
auto func_add1 = [=](int a, int b)
{
a = 1; //这里修改的只是形参a/b的值,不会改变num1与num2的值
b = 1;
return a + b;
};
auto func_add2 = [&]
{
// num1 = 1; //按引用传递,可用可修改num1与num2的值
return num1 + num2;
};
cout<#include
#include
#include
using namespace std;
template
class Add
{
public:
Add() = default;
void operator()(T &&a, T &&b) //重载函数运算符,采用的是万能引用
{
cout< c_add;
c_add.operator()(5,6); //利用成员函数的形式调用
c_add(5,6); //采用函数成员方式
plus p1;
cout<
(2)函数对象(function object)与普通函数的区别
①函数对象比一般函数更灵活,因为它可以拥有状态(state),事实上,对于相同的函数对象可以设置两个状态不同的实例;普通函数没有状态;
②每个函数对象都有其类型,因为你可以将函数对象的类型当做template参数传递,从而指定某种行为;另外容器类型也会因为函数对象的不同而不同;
③执行速度上,函数对象通常比函数指针更快;
3. 函数包装器
(1)本质与作用
①统一所有的函数调用形式,全部面向对象
②本质是一个类模板,用于包装可调用对象,可以容纳除了类成员之外(函数)指针之外的所有可调用形式;
③头文件:#include
#include
#include
#include
using namespace std;
template
class Add
{
public:
Add() = default;
void operator()(T &&a, T &&b)
{
cout< c_add;
auto f_add = [](int a, int b) //lambda表达式
{
return a + b;
};
//函数包装器,统一所有的函数调用形式,全部面向对象;
functionfunc1(add); //对普通函数包装
cout<<"add : "<func2(f_add); //对lambda表达式包装
cout<<"lambda : "<func3(c_add); //对函数对象包装
cout<<"functor : ";
func3(5,6);
return 0;
}
4. bind 函数适配器
(1)主要用在函数已经存在,但是现有参数较多,减少实际所需参数个数的一种方法;
(2)本质,bind也是一个函数模板,返回值是一个仿函数,是可调用对象;
(3)bind可以绑定的对象:①普通函数;②lambda表达式;③函数对象;④类的成员函数;⑤类的数据成员;
示例:
#include
#include
using namespace std;
template
class Add
{
public:
T operator()(T a, T b, T c)
{
print();
return a + b;
}
void operator()(const T &a)
{
cout << a << endl;
}
void print()
{
cout << "function add!" << endl;
}
int m_result;
};
int add(int a, int b, int c)
{
cout << "a = " << a << " b = " << b << endl;
return a + b + c;
}
int main()
{
//普通函数
function my_add = std::bind(add,std::placeholders::_1,std::placeholders::_2,0);
cout << my_add(5,6) << endl;
function my_add2 = std::bind(add,7,8,0);
cout << my_add2() << endl;
//lambda表达式
auto lambda_func = [=](int a, int b, int c)
{
return a + b + c;
};
function my_add3 = std::bind(lambda_func,std::placeholders::_2,std::placeholders::_1,0);
cout << my_add3(3,4) << endl;
function my_add4 = std::bind(lambda_func,3,4,0);
cout << my_add4() << endl;
//函数对象
Add c_add;
function my_add5 = std::bind(c_add,std::placeholders::_2,std::placeholders::_1,0);
cout << my_add5(4,5) << endl;
function my_add6 = std::bind(c_add,5,6,0);
cout << my_add6() << endl;
return 0;
}
5. 关键字constexpr
(1)引入的原因:因为const不能确保其修饰的变量、函数能够在编译器优化,从而引入constexpr确保被其修饰的变量或者函数能够在编译器优化;从c++11开始引入;
(2)主要的优点:让函数执行提前到编译期,减少函数调用返回的消耗;
(3)注意点
①修饰变量时:变量必须是常量、变量必须立即被初始化、变量的类型不可以是类类型;
②修饰表达式时:表达式的值不会改变且在编译期就可求值的表达式;
③修饰指针时:仅对指针有效,与指向的对象无关,即指针的指向不可发生变化;
④constexpr修饰的函数中不可以出现循环体;且函数必须不能是虚函数(基类中被virtual修饰的成员函数);函数体中不可以出现try和goto语句;constex只可以调用其他conste函数,不可以调用非conste函数;