哪里有学做ppt的网站,网站建设厃金手指花总十一,长春网站开发报价,ae资源网免费一、可变参数模板
C11的新特性可变参数模板 能够让您创建可以接受 可变参数的函数模板和类模板
// Args是一个模板参数包#xff0c;args是一个函数形参参数包
// 声明一个参数包Args...args#xff0c;这个参数包中可以包含0到任意个模板参数。
template class ...Arg…
一、可变参数模板
C11的新特性可变参数模板 能够让您创建可以接受 可变参数的函数模板和类模板
// Args是一个模板参数包args是一个函数形参参数包
// 声明一个参数包Args...args这个参数包中可以包含0到任意个模板参数。
template class ...Args
void ShowList(Args... args)
{}参数包是不支持下标解析的
1.1 递归函数方式展开参数包
// 递归终止函数
void ShowList()
{cout endl;
}// 展开函数
// 增加一个模板参数让编译器自己去解析这个参数包里的东西
template class T, class ...Args
void ShowList(const T value, Args... args)
{cout value ;ShowList(args...); // 如果是0个参数的参数包就会调用void ShowList()// 如果参数包接收的char类型的参数会再去调匹配的ShowList函数// 调不到就只能调自己根据模板推导类型// 打印完参数包再往下传0个参数就调用void ShowList()// void ShowList()可以认为是递归终止函数
}int main()
{ShowList(); // 编译器会找最匹配的调void ShowList()ShowList(1); // 1传给value后面的参数包就没有了参数包代表0-n个参数ShowList(1, A); // 1传给valueA传给参数包ShowList(1, A, std::string(sort));return 0;
}二、lambda表达式
C98中 对一个数据集合中的元素排序 可以使用std::sort
如果待排序元素为自定义类型 需要自己写仿函数 如果每次按自定义类型不同的成员变量 进行排序就要写多个仿函数,十分不方便 因此,C11语法中的Lambda表达式 便是解决此类问题
lambda表达式
int main()
{vectorGoods v { { 苹果, 2.1, 5 }, { 香蕉, 3, 4 }, { 橙子, 2.2, 3 }, { 菠萝, 1.5, 4 } };sort(v.begin(), v.end(), [](const Goods g1, const Goods g2){return g1._price g2._price; });sort(v.begin(), v.end(), [](const Goods g1, const Goods g2){return g1._price g2._price; });sort(v.begin(), v.end(), [](const Goods g1, const Goods g2){return g1._evaluate g2._evaluate; });sort(v.begin(), v.end(), [](const Goods g1, const Goods g2){return g1._evaluate g2._evaluate; });
}可以发现lambda表达式是一个匿名函数
1.1 lambda表达式语法
书写格式: [捕捉列表] (参数列表) mutable -return-type { 函数体 }
捕捉列表该列表总出现lambda函数开始位置 编译器根据[]判断接下来的代码是否为lambda函数 捕捉列表能够捕捉上下文中的变量供lambda函数使用参数列表与普通函数的参数列表一致 如果不需要参数传递则可以连同()一起省略mutable默认情况lambda函数总是const函数mutable可以取消其常量性 使用该修饰符参数列表不可省略(即使参数为空)-return-type返回值类型 用追踪返回类型形式声明函数的返回值类型 无返回值可略有返回值也可略由编译器推导{ 函数体 }该函数体内除了可使用其参数外 还可以使用所有捕获到的变量
用lambda表达式实现add
auto add [](int x, int y)-int { return x y; };// cout [](int x, int y)-int { return x y; }(1, 2) endl; // 这样写比较抽象
cout add(1, 2) endl;auto add2 [](int x, int y)
{ return x y;
};
cout add2(3, 2) endl;[] {}; // 最简单的lambda,捕捉列表和函数体是一定不能省略的用lambda对自定义类型比较大小
struct Goods
{string _name; // 名字double _price; // 价格int _evaluate; // 评价Goods(const char* str, double price, int evaluate):_name(str), _price(price), _evaluate(evaluate){}
};int main()
{vectorGoods v { { 苹果, 2.1, 5 }, { 香蕉, 3, 4 }, { 橙子, 2.2, 3 }, { 菠萝, 1.5, 4 } };// 用lambda对自定义类型比较大小// auto priceLess [](const Goods g1, const Goods g2)-bool { return g1._price g2._price; };sort(v.begin(), v.end(), priceLess);// sort(v.begin(), v.end(), [](const Goods g1, const Goods g2)-bool { return g1._price g2._price; });// 比较评价sort(v.begin(), v.end(), [](const Goods g1, const Goods g2)-bool {return g1._evaluate g2._evaluate; });sort(v.begin(), v.end(), [](const Goods g1, const Goods g2)-bool {return g1._evaluate g2._evaluate; });return 0;
}捕捉变量
int main()
{int x 1, y 2;auto swap1 [](int rx, int ry){// 只能用当前作用域的变量int tmp rx;rx ry;ry tmp;};swap1(x, y);cout x y endl;// 还可以换一种写法// 想用外面的变量,则可以利用捕捉列表进行捕捉(捕捉过来的对象是外面对象的拷贝)/*// 传值捕捉auto swap2 [x, y]() mutable // 捕捉多个值用逗号分割即可;直接给值叫做传值捕捉,传值捕捉无法修改,加上mutable(异变)就可以修改{int tmp x;x y;y tmp;};swap2();cout x y endl;*/// mutable用得比较少,建议// 引用捕捉auto swap2 [x, y](){int tmp x;x y;y tmp;};swap2();cout x y endl;// 还可以混合捕捉,x引用捕捉,y传值捕捉// 全部引用捕捉auto func1 [](){// ...};// 全部传值捕捉auto func2 [](){// ...};// 全部引用捕捉,x传值捕捉auto func3 [, x](){// ...};return 0;
}1.2 函数对象与lambda表达式
函数对象又称为仿函数 即可像函数一样使用的对象 (在类中重载了operator()运算符的类对象)
class Rate
{
public:Rate(double rate): _rate(rate){}double operator()(double money, int year){ return money * _rate * year;}
private:double _rate;
};
int main()
{
// 函数对象double rate 0.49;Rate r1(rate);r1(10000, 2);
// lamberauto r2 [](double monty, int year)-double{return monty*rate*year;
};r2(10000, 2);return 0;
}lambda表达式大小为1个字节 在编译器角度是没有lambda 定义一个lambda 编译器自动生成一个仿函数对象的类型 在该类中重载了operator() 该类是一个空类,空类没给成员变量就是一个字节 函数对象将rate作为其成员变量 在定义对象时给出初始值即可 lambda表达式通过捕获列表可以 直接将该变量捕获到 三、包装器
C中的function本质是一个类模板 也是一个包装器
int f(int a, int b)
{return a b;
}struct Functor
{
public:int operator()(int a, int b){return a b;}
};int main()
{// int(*pf1)(int, int) f; // 不是常规的指针类型,写法复杂// 假设要求要声明一个统一的类型// mapstring, // 这里要声明可调用类型,f和Functor调用起来都是一样的,但类型不一样,一个是函数指针一个是类// 这时候就没法声明,而包装器就可以统一封装出可调用类型functionint(int, int) f1 f; // 返回值加参数包,参数包就是把实际要的类型写上functionint(int, int) f2 Functor(); // Function可以对函数指针和仿函数对象进行包装functionint(int, int) f3 [](int a, int b) { return a b; };cout f1(1, 2) endl; // 包装以后两个类型的对象是一样的cout f2(2, 2) endl;cout f3(3, 3) endl;mapstring, functionint(int, int) opFuncMap; opFuncMap[函数指针] f;opFuncMap[仿函数] Functor();opFuncMap[lambda] [](int a, int b) { return a b; };// 包装器的作用:更好的控制可调用对象的类型return 0;
}静态成员和非静态成员的包装
class Plus
{
public:Plus(int rate): _rate(rate){}static int plusi(int a, int b){return a b;}double plusd(double a, double b){return (a b) * _rate;}
private:int _rate 2;
};int main()
{functionint(int, int) f1 Plus::plusi; // 包装静态成员函数正常包装就可以// 非静态成员函数,就不能这样直接包装// functiondouble(double, double) f2 Plus::plusd;// error C3867: “Plus::plusd”: 非标准语法请使用 来创建指向成员的指针// 普通成员函数名代表函数指针.静态成员也一样,指定类域就可取到这个函数指针// 非静态成员需要加一个// 非静态传参还有一个this指针需要传参// error C2440 : “初始化”: 无法从“double(__cdecl Plus::*)(double, double)”转换为“std::functiondouble(double, double)”functiondouble(Plus, double, double) f2 Plus::plusd; // 也可以传Plus*,左值能被取地址,右值不行,匿名对象是右值不能取地址,就不能用匿名对象// 传指针也可以,传对象也可以,因为这不是直接去掉用plusd这个函数,我是一个包装器,f1是直接调用Plusi// f2是用对象去掉用Plusd// 当Plusd是指针,就用指针取调用Plusd// 如果是对象就用对象调用Plusd cout f1(1, 2) endl;cout f2(Plus(2), 20, 20) endl; // 第一个正常调用,第二个需要加一个匿名对象;需要写一个构造函数,也可以不写,Plus就不能传参// 也可以不用匿名对象Plus p1(3);cout f2(p1, 20, 20) endl;return 0;
}bind
调整参数顺序
void Print(int a, int b)
{cout a ;cout b endl;
}int main()
{Print(10, 20); // auto RPrint bind(Print, placeholders::_2, placeholders::_1); // 第一个参数传可调用对象,_1是一个占位符也是第一个参数,-2是第二个参数以此类推,默认是拿不到的,它放在placeholders命名空间里面functionvoid(int, int) RPrint bind(Print, placeholders::_2, placeholders::_1);// 两种写法都可以推荐用autoRPrint(10, 20);return 0;
}调整参数个数
class Sub
{
public:Sub(int rate): _rate(rate){}int func(int a, int b){return (a - b) * _rate;}
private:int _rate;
};int main()
{functionint(Sub, int, int) fSub Sub::func;cout fSub(Sub(3), 10, 20) endl;functionint(int, int) fSub1 bind(Sub::func, Sub(3), placeholders::_1, placeholders::_2);cout fSub1(10, 20) endl;// 把隐藏this指针绑死就只用传两个参数// 把第二个参数绑死functionint(Sub, int) fSub2 bind(Sub::func, placeholders::_1, 100, placeholders::_2);// 第二个参数绑死了,第三个参数是_2,还是按顺序挨着走 cout fSub2(Sub(3), 20) endl;}本篇博客完感谢阅读 如有错误之处可评论指出 博主会耐心听取每条意见