当前位置: 首页 > news >正文

外贸公司手机网站网站这么做

外贸公司手机网站,网站这么做,防疫测温健康码核验一体机,浙江省建设厅干部学校门户网站目录 1. 可变参数模板 1.1 展开参数包 1.1.1 递归函数方式展开 1.1.2 逗号表达式展开 1.2 emplace相关接口 2. lambda表达式#xff08;匿名函数#xff09; 2.1 C11之前函数的缺陷 2.2 lambda表达式语法 2.3 函数对象与lambda表达式 3. 包装器 3.1 function包装器…目录 1. 可变参数模板 1.1 展开参数包 1.1.1 递归函数方式展开 1.1.2 逗号表达式展开 1.2 emplace相关接口 2. lambda表达式匿名函数 2.1 C11之前函数的缺陷 2.2 lambda表达式语法 2.3 函数对象与lambda表达式 3. 包装器 3.1 function包装器 3.1.1 function包装器使用 3.1.2 function的场景力扣150逆波兰表达式求值 3.2 bind绑定 4. 笔试选择题 答案及解析 本篇完。 1. 可变参数模板 C11的新特性可变参数模板能够让您创建可以接受可变参数的函数模板和类模板相比 C98/03类模版和函数模版中只能含固定数量的模版参数可变模版参数无疑是一个巨大的改进。然而由于可变模版参数比较抽象使用起来需要一定的技巧所以这块还是比较晦涩的。现阶段我们掌握一些基础的可变参数模板特性就够我们用了所以这里我们点到为止以后如果有需要再可以深入学习。 下面就是一个基本可变参数的函数模板 template class ...Args void ShowList(Args... args) {//....... }声明一个参数包Args...args这个参数包中可以包含0到NN0个模板参数。Args是一个模板参数包args是一个函数形参参数包 上面的参数args前面有省略号所以它就是一个可变模版参数我们把带省略号的参数称为“参数包”它里面包含了0到NN0个模版参数。我们无法直接获取参数包args中的每个参数的 只能通过展开参数包的方式来获取参数包中的每个参数这是使用可变模版参数的一个主要特点也是最大的难点即如何展开可变模版参数。由于语法不支持使用args[i]这样方式获取可变参数所以我们的用一些奇招来一一获取参数包的值。 在使用可变参数模板的时候可以传入任意个类型的数据编译器会将所有类型打包。 可变参数模板的难点就是如果展开参数包从而使用里面的每个模板参数。 1.1 展开参数包 1.1.1 递归函数方式展开 template class T// 递归终止函数 void ShowList(const T t) {cout t endl; }template class T, class ...Args// 展开函数 void ShowList(T value, Args... args) {cout value ;ShowList(args...); }int main() {ShowList(1);ShowList(1, R);ShowList(1, R, std::string(left));return 0; } 调用同一个函数模板传入不同个数的参数函数模板都能将这些变化的参数打印出来。 如上图灵魂画手这种方式很像递归在函数模板中调用函数模板通过模板参数中的第一个模板参数一个个从参数包中拿参数。不需要的形参的函数就相当于一个结束条件。 1.1.2 逗号表达式展开 template class T void PrintArg(T t) {cout t ; }template class ...Args//展开函数 void ShowList(Args... args) {int arr[] { (PrintArg(args), 0)... };cout endl; }int main() {ShowList(1);ShowList(1, R);ShowList(1, R, std::string(left));return 0; } 同样将参数包挨个展开了。 逗号表达式的结果是最右边的值。 这种展开参数包的方式不需要通过递归终止函数是直接在ShowList函数体中展开的, PrintArg不是一个递归终止函数只是一个处理参数包中每一个参数的函数。这种就地展开参数包的方式实现的关键是逗号表达式。我们知道逗号表达式会按顺序执行逗号前面的表达式。 ShowList函数中的逗号表达式(PrintArg(args), 0)也是按照这个执行顺序先执行 PrintArg(args)再得到逗号表达式的结果0。同时还用到了C11的另外一个特性——初始化列表通过初始化列表来初始化一个变长数组, {(PrintArg(args), 0)...}将会展开成((PrintArg(arg1),0), (PrintArg(arg2),0), (PrintArg(arg3),0), etc... )最终会创建一个元素值都为0的数组int arr[sizeof(Args)]。由于是逗号表达式在创建数组的过程中会先执行逗号表达式前面的部分PrintArg(args) 打印出参数也就是说在构造int数组的过程中就将参数包展开了这个数组的目的纯粹是为了在数组构造的过程展开参数包 逗号表达式简化的代码 template class T int PrintArg(T t) {cout t ;return 0; }template class ...Args//展开函数 void ShowList(Args... args) {int arr[] { PrintArg(args)... };cout endl; }int main() {ShowList(1);ShowList(1, R);ShowList(1, R, std::string(left));return 0; } 采用上图所示方式也可以展开参数包。 在ShowList中的数组中多次调用PrintArg函数每次调用后返回值是0。 多个0形参的列表初始化数组。 这种方式中看起来比逗号表达式好理解数组同样仅起辅助作用。 1.2 emplace相关接口 C11基于可变参数模板在STL中提供了emplace相关的接口 emplace的作用和insert类似emplace_back的作用和push_back相似。 上图是以vector为例其他STL容器也有emplace系列的相关接口。 emplace接口也是模板函数它既是一个万能引用模板也是一个可变参数模板可以称为万能引用可变参数模板。无论插入的数据是左值还是右值无论是多少个都可插入。 int main() {listint mylist;mylist.push_back(10);mylist.push_back(20);mylist.emplace_back(30);mylist.emplace_back(40);//mylist.emplace_back(50, 60); //不能这样用for (const auto e : mylist){cout e endl;}return 0; } 对于内置类型push_back和emplace_back没有任何区别。而且也不可以一次性插入多个内置类型的值。 只有对容器实例化后并且存放多个值时才能使用empalce_back一次性插入 int main() {listpairint, char mylist;mylist.push_back({ 10, a });mylist.emplace_back(20, b);mylist.push_back(make_pair(30, c));mylist.emplace_back(make_pair(40, d));mylist.emplace_back(50, e);for (const auto e : mylist){cout e.first : e.second endl;}return 0; } emplace相关接口的优势 将上篇文章C11——新特性 | 右值引用 | 完美转发中的string复制过来在用字符串的构造的构造函数中打印提示信息使用push_back插入不同类型的值 namespace rtx {class string{public:string(const char* str ):_size(strlen(str)), _capacity(_size){_str new char[_capacity 1];strcpy(_str, str);cout string(const char* str ) -- 构造函数 endl;}void swap(string s){::swap(_str, s._str);::swap(_size, s._size);::swap(_capacity, s._capacity);}string(const string s) // 拷贝构造:_str(nullptr), _size(0), _capacity(0){cout string(const string s) -- 拷贝构造(深拷贝) endl;string tmp(s._str);swap(tmp);}string(string s) // 移动构造:_str(nullptr), _size(0), _capacity(0){cout string(string s) -- 移动构造(资源转移) endl;swap(s);}string operator(const string s) // 拷贝赋值{cout string operator(string s) -- 拷贝赋值(深拷贝) endl;string tmp(s);swap(tmp);return *this;}string operator(string s) // 移动赋值{cout string operator(string s) -- 移动赋值(资源移动) endl;swap(s);return *this;}~string(){delete[] _str;_str nullptr;}void reserve(size_t n){if (n _capacity){char* tmp new char[n 1];strcpy(tmp, _str);delete[] _str;_str tmp;_capacity n;}}void push_back(char ch){if (_size _capacity){size_t newcapacity _capacity 0 ? 4 : _capacity * 2;reserve(newcapacity);}_str[_size] ch;_size;_str[_size] \0;}protected:char* _str;size_t _size;size_t _capacity;}; }int main() {std::list std::pairint, rtx::string mylist;mylist.emplace_back(10, sort);mylist.emplace_back(make_pair(20, sort));cout ######################################### endl;mylist.push_back(make_pair(30, sort));mylist.push_back({ 40, sort });return 0; } 据此对比发现 插入左值时emplace_back和push_back没有区别。 因为左值无论是编译器还是emplace_back都是不敢进行优化的只能老老实实进行深拷贝以防影响到原本的左值。 插入右值(匿名键值对)时emplace_back仅调用了构造函数。 在插入的过程中匿名对象一直存在没有被转移资源知道链表在new一个新节点的时候才用右值对象中的数据来初始化节点其中string调用的是普通构造函数是用右值中的字符串来初始化的。 插入多个值(可变参数)时emplace_back仅调用了构造函数。 和插入右值一样只有在new一个新节点的时候多个插入的值才被用来初始化所以也是只调用了普通构造函数。 只有在插入自定义类型的右值时emplace_back的效率才比push_back高。emplace_back比push_back少调用了一个移动构造函数 我们知道移动构造是将右值的资源进行转移也是非常高效的代价非常小。 emplace系列接口在存在移动构造的情况下并不能比push_back高效很多但还是高一点的。 如果没有移动构造 使用emplace_back插入左值和右值。  对于左值仍然需要深拷贝。 对于右值则仅调用了构造函数不用进行拷贝构造而发生深拷贝。 emplace_back相比于push_back少调用了拷贝构造没有进行深拷贝大大提高了效率降低了系统开销。 对于不存在移动构造的情况下emplace相关接口比push_back高效很多。 所以以后用push_back系列的时候都可以用emplace_back系列替代。想到就行 2. lambda表达式匿名函数 2.1 C11之前函数的缺陷 在C98中如果想要对一个数据集合中的元素进行排序可以使用std::sort方法。 #include algorithm #include functional int main() {int arr[] { 4,1,8,5,3,7,0,9,2,6 };// 默认按照小于比较排出来结果是升序std::sort(arr, arr sizeof(arr) / sizeof(arr[0]));// 如果需要降序需要改变元素的比较规则std::sort(arr, arr sizeof(arr) / sizeof(arr[0]), greaterint());return 0; } 如果待排序元素为自定义类型需要用户定义排序时的比较规则 struct Goods {string _name; // 名字double _price; // 价格int _evaluate; // 评价Goods(const char* str, double price, int evaluate):_name(str), _price(price), _evaluate(evaluate){} }; struct ComparePriceLess {bool operator()(const Goods gl, const Goods gr){return gl._price gr._price;} }; struct ComparePriceGreater {bool operator()(const Goods gl, const Goods gr){return gl._price gr._price;} }; int main() {vectorGoods v { { 苹果, 2.1, 5 }, { 香蕉, 3, 7 }, { 西瓜, 5.5,3 }, { 橘子, 7.7, 4 } };sort(v.begin(), v.end(), ComparePriceLess());sort(v.begin(), v.end(), ComparePriceGreater()); } 随着C语法的发展人们开始觉得上面的写法太复杂了每次为了实现一个algorithm算法 都要重新去写一个类如果每次比较的逻辑不一样还要去实现多个类特别是相同类的命名可能导致命名不规范 这些都给编程者带来了极大的不便。因此在C11语法中出现了Lambda表达式。 2.2 lambda表达式语法 lambda表达式书写格式 [capture-list] (parameters) mutable - return-type { statement } 即 [捕捉列表](参数列表)mutable-(返回值类型){函数体}[捕捉列表] 捕捉列表是编译器判断lambda表达式的依据所以必须写[][]内可以有参数后面详细讲解。 (参数列表) 参数列表和普通函数的参数列表一样如果不需要参数传递可以连同()一起省略。 mutable 默认情况下lambda表达式的形参都是const类型形参不可以被修改使用mutable可以取消形参的常量属性。使用mutable时参数列表不可以省略(即使参数为空)。一般情况下mutable都是省略的。 -返回值类型 -和返回值类型是一体的如-int表示lambda的返回值是int类型。一般情况下省略-返回值类型因为编译器可以根据函数体中的return推导出返回值类型。为了提高程序的可读性可以写上。 {函数体} 和普通函数一样{ }里的是lambda的具体实现逻辑。 注意 在lambda函数定义中参数列表和返回值类型都是可选部分可写可不写。 而捕捉列表和函数体必须写但是内容可以为空。因此C11中最简单的lambda函数为[ ]{ }; 该lambda函数不能做任何事情。 写两个简单的lambda int main() {// 两个数相加的lambdaauto add1 [](int a, int b)-int {return a b;};auto add2 [](int a, int b) {return a b;};cout add1(1, 6) endl;cout add2(1, 6) endl;return 0; } C11之前函数的缺陷例子用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, 7 }, { 西瓜, 5.5,3 }, { 橘子, 7.7, 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; });return 0; } 交换变量的lambda int main() {// 交换变量的lambdaint x 0, y 7;auto swap1 [](int x1, int x2)-void{int tmp x1; x1 x2; x2 tmp; };swap1(x, y);cout x ------- y endl;auto swap2 [](int x1, int x2){int tmp x1;x1 x2;x2 tmp;};swap2(x, y);cout x ------- y endl;return 0; } 能不能不传参数交换x和y呢用上捕捉列表就行 int main() {// 交换变量的lambdaint x 0, y 7;auto swap1 [](int x1, int x2)-void{int tmp x1; x1 x2; x2 tmp; };swap1(x, y);cout x ------- y endl;auto swap2 [](int x1, int x2){int tmp x1;x1 x2;x2 tmp;};swap2(x, y);cout x ------- y endl;auto swap3 [x, y](int x1, int x2){int tmp x1;x1 x2;x2 tmp;};swap3(x, y);cout x ------- y endl;swap3(x, y);cout x ------- y endl;return 0; } 捕获列表说明 捕捉列表描述了上下文中那些数据可以被lambda使用以及使用的方式传值还是传引用。 [var]表示值传递方式捕捉变量var[]表示值传递方式捕获所有父作用域中的变量(包括this)[var]表示引用传递捕捉变量var捕捉不是传参捕捉中就不存在取地址这一语法。[]表示引用传递捕捉所有父作用域中的变量(包括this) 注意 ① 父作用域指包含lambda函数的语句块。 ② 语法上捕捉列表可由多个捕捉项组成并以逗号分割。比如[, a, b]以引用传递的方式捕捉变量a和b值传递方式捕捉其他所有变量 [a, this]值传递方式捕捉变量a和this引用方式捕捉其他变量。 ③ 捕捉列表不允许变量重复传递否则就会导致编译错误。 比如[, a]已经以值传递方式捕捉了所有变量捕捉a重复。 ④ 在块作用域以外的lambda函数捕捉列表必须为空。 ⑤ 在块作用域中的lambda函数仅能捕捉父作用域中局部变量捕捉任何非此作用域或者非局部变量都会导致编译报错。 ⑥ lambda表达式之间不能相互赋值即使看起来类型相同。 简单使用 int main() {int a, b, c, d, e;a b c d e 1;auto f1 []() // 全部传值捕捉{cout a b c d e endl;};f1();auto f2 [, a]() // 混合捕捉{a;cout a b c d e endl;};f2();return 0; } 2.3 函数对象与lambda表达式 函数对象又称为仿函数即可以像函数一样使用的对象就是在类中重载了operator()运算符的类对象。 class Rate { public:Rate(double rate) : _rate(rate){}double operator()(double money, int year){return money * year * _rate;} private:double _rate; };int main() {// 函数对象double rate 0.5;Rate r1(rate);cout r1(518, 3) endl;// lamberauto r2 [](double money, int year)-double {return money * year * rate;};cout r2(518, 3) endl;return 0; } 使用函数对象和lambda两种方式进行利率计算执行的函数体内容相同。 从使用方式上来看函数对象和lambda表达式完全一样如中r1和r2所示。 rate是函数对象的成员变量通过构造函数初始化lambda通过捕获列表来捕获该变量。 调试起来后查看汇编代码如上图所示是调用函数对象部分的汇编代码。 创建函数对象时调用了Rate类域中的构造函数。 调用函数对象时调用了Rate类域中的operator()成员函数。 上图所示是lambda表达式部分的汇编代码。 创建lambda表达式时也是调用了某个类中的构造函数。 该类不像函数对象那样明确而是有很长一串如上图所示的lambda_0d841c589991fabbf3e571d463f613ab。 调用lambda表达式时调用的是该类中的operator()成员函数。 函数对象和lambda在汇编代码上是一样的只是类不同而已。函数对象的类名是我们自己定义的。 lambda的类名是编译器自己生成的。 编译器在遇到lambda表达式的时候会执行一个算法生成长串数字而且几乎每次生成的数字都不同也就意味着每次创建的类名都不同。 lambda表达式的类型只有编译器自己知道用户是无法知道的。 所以要通过auto来推演它的类型才能接收这个匿名的函数对象。 lambda表达式和函数对象其实是一回事只是lambda表达式的类是由编译器自动生成的。 此时应该就理解了为什么说lambda其实就是一个匿名的函数对象了吧。 所以lambda表达式相互不可以赋值因为编译器生成的类不一样也就意味着不是一个类型。 3. 包装器 3.1 function包装器 function包装器也叫作适配器。 C中的function本质是一个类模板也是一个包装器。 我们为什么需要function呢 ret func(x); 上面func可能是什么呢那么func可能是函数名函数指针函数对象(仿函数对象)也有可能 是lamber表达式对象所以这些都是可调用的类型如此丰富的类型可能会导致模板的效率低下。为什么呢往下看 templateclass F, class T T useF(F f, T x) {static int count 0;cout count: count endl;cout count: count endl;return f(x); } double f(double i) {return i / 2; } struct Functor {double operator()(double d){return d / 3;} }; int main() {// 函数名cout useF(f, 11.11) endl;// 函数对象cout useF(Functor(), 11.11) endl;// lamber表达式对象cout useF([](double d)-double { return d / 4; }, 11.11) endl;return 0; } 通过上面的程序验证我们会发现useF函数模板实例化了三份。 3.1.1 function包装器使用 包装器可以很好的解决上面的问题  std::function在头文件functional 类模板原型如下 template class T function;     // undefined template class Ret, class... Args class functionRet(Args...); 模板参数说明 Ret: 被调用函数的返回类型 Args…被调用函数的形参 function包装器使用 int f(int a, int b) {return a b; } struct Functor { public:int operator() (int a, int b){return a b;} }; class Plus { public:static int plusi(int a, int b){return a b;}double plusd(double a, double b){return a b;} }; int main() {std::functionint(int, int) func1 f; // 函数名(函数指针)cout func1(1, 2) endl;std::functionint(int, int) func2 Functor(); // 函数对象cout func2(1, 2) endl;std::functionint(int, int) func3 [](const int a, const int b){return a b; }; // lamber表达式cout func3(1, 2) endl;std::functionint(int, int) func4 Plus::plusi; // 类的静态成员函数cout func4(1, 2) endl;std::functiondouble(Plus, double, double) func5 Plus::plusd;cout func5(Plus(), 1.1, 2.2) endl; // 类的成员函数需要用对象调用return 0; } function包装器解决模板的效率低下问题 templateclass F, class T T useF(F f, T x) {static int count 0;cout count: count endl;cout count: count endl;return f(x); } double f(double i) {return i / 2; } struct Functor {double operator()(double d){return d / 3;} }; int main() {// 函数名functiondouble(double) f1 f;cout useF(f1, 11.11) endl;// 函数对象functiondouble(double) f2 Functor();cout useF(f2, 11.11) endl;// lamber表达式对象functiondouble(double) f3 [](double d)-double { return d / 4; };cout useF(f3, 11.11) endl;return 0; } useF函数模板只实例化了一份。 3.1.2 function的场景力扣150逆波兰表达式求值 包装器的其他一些场景以前写过的题目 150. 逆波兰表达式求值 - 力扣LeetCode 给你一个字符串数组 tokens 表示一个根据 逆波兰表示法 表示的算术表达式。 请你计算该表达式。返回一个表示表达式值的整数。 注意 有效的算符为 、-、* 和 / 。每个操作数运算对象都可以是一个整数或者另一个表达式。两个整数之间的除法总是 向零截断 。表达式中不含除零运算。输入是一个根据逆波兰表示法表示的算术表达式。答案及所有中间计算结果可以用 32 位 整数表示。 以前的思路和代码逆波兰表达式严格遵循「从左到右」的运算。计算逆波兰表达式的值时使用一个栈存储操作数从左到右遍历逆波兰表达式进行如下操作 如果遇到操作数则将操作数入栈 如果遇到运算符则将两个操作数出栈其中先出栈的是右操作数 后出栈的是左操作数使用运算符对两个操作数进行运算将运算得到的新操作数入栈。 整个逆波兰表达式遍历完毕之后栈内只有一个元素该元素即为逆波兰表达式的值。 简单来说就是① 操作数入栈       ② 遇到操作符就取栈顶两个操作数运算 //1 操作数入栈 //2 遇到操作符就取栈顶两个操作数运算 class Solution { public:int evalRPN(vectorstring tokens) {stackint st;for(auto e: tokens){if(e || e - || e * || e /){int right st.top();//右操作数先出栈st.pop();int left st.top();st.pop();switch(e[0]){case :st.push(left right);break;case -:st.push(left - right);break;case *:st.push(left * right);break;case /:st.push(left / right);break;}}else{st.push(stoi(e));}}return st.top();} }; 用了lambda表达式和function包装器的代码测试改了用long long class Solution { public:int evalRPN(vectorstring tokens) {stacklong long st;mapstring, functionlong long(long long, long long) opFuncMap {{, [](long long a, long long b) {return a b;}},{-, [](long long a, long long b) {return a - b;}},{*, [](long long a, long long b) {return a * b;}},{/, [](long long a, long long b) {return a / b;}},};for (auto str : tokens){if (opFuncMap.count(str)) // 操作符{int right st.top();//右操作数先出栈st.pop();int left st.top();st.pop();st.push(opFuncMap[str](left, right));}else // 操作数{st.push(stoll(str));}}return st.top();} }; 3.2 bind绑定 学了包装器如果出现以下这种场景怎么办 int Plus(int a, int b) {return a b; } class Sub { public:int sub(int a, int b){return a - b;} }; int main() {//functionint(int, int) funcPlus Plus;//functionint(Sub, int, int) funcSub Sub::sub; // 类内函数要传类,多一个参数mapstring, functionint(int, int) opFuncMap {{ , Plus},{ -, Sub::sub}};return 0; } 这时包装器“包不了了”类内函数要传类多一个参数此时bind就来了 bind也叫做绑定是一个函数模板返回一个function它就像一个函数包装器(适配器)接受一个可调用对象生成一个新的可调用对象来“适应”原对象的参数列表。 这是一个万能引用模板除了可调用对象模板参数外其他参数是可变参数也就是一个参数包。 int Plus(int a, int b) {return a b; } class Sub { public:int sub(int a, int b){return a - b;} }; using namespace placeholders; // _1, _2 要加命名空间 int main() {//functionint(int, int) funcPlus Plus;//functionint(Sub, int, int) funcSub Sub::sub; // 类内函数要传类,多一个参数//mapstring, functionint(int, int) opFuncMap //{// { , Plus},// { -, Sub::sub}//};//functionint(int, int) funcPlus Plus;//functionint(int, int) funcSub bind(Sub::sub, Sub(), _1, _2);mapstring, functionint(int, int) opFuncMap {{ , Plus},{ -, bind(Sub::sub, Sub(), _1, _2)}};return 0; } 这里用bind绑定了第一个参数固定住了成功运行。 还有调整顺序的功能 int Sub(int a, int b) {return a - b; } using namespace placeholders; // _1, _2 要加命名空间 int main() {int x 2, y 9;cout Sub(x, y) endl;//_1 _2.... 定义在placeholders命名空间中代表绑定函数对象的形参//_1_2...分别代表第一个形参、第二个形参...//functionint(int, int) bindFunc1 bind(Sub, _1, _2); // 没换顺序//functionint(int, int) bindFunc2 bind(Sub, _2, _1); // 换顺序了auto bindFunc1 bind(Sub, _1, _2); // 没换顺序auto bindFunc2 bind(Sub, _2, _1); // 换顺序了cout bindFunc1(x, y) endl;cout bindFunc2(x, y) endl;return 0; } 调整顺序的功能比较鸡肋很少用除非特殊场景bind用来占位比较常用。 4. 笔试选择题 1. 下面关于范围for说法错误的是 A.范围for可以直接应用在数组上 B.对于STL提供的所有容器均可以使用for依次访问器元素 C.使用范围for操作stack可以简化代码 D.对于自定义类型想要支持范围for必须提供begin和end迭代器 E.范围for编译器最终是将其转化为迭代器来进行处理的 2. 下面关于列表初始化说法错误的是 A.在C98中{}只能用来初始化数组 B.在C98中new单个int类型空间可以直接初始化new一段连续int类型空间不能直接初始化 C.在C11中{}的初始化范围增大了任意类型都可以初始化 D.使用{}初始化时必须要加号 3. 下面关于auto的说法错误的是 A.auto主要用于类型推导可以让代码的书写更简洁 B.在C11中auto即可以用来声明自动类型变量也可以用来进行变量类型推导 C.auto不能推导函数参数的类型 D.auto是占位符在编译阶段推演出初始化表达式的实际类型来替换auto位置 4. 下列关于final说法正确的是 A.final只能修饰类表示该类不能被继承 B.final可以修饰任意成员函数 C.final修饰成员函数时表示该函数不能被子类继承 D.final修饰派生类虚函数时表示该虚函数再不能被其子类重写 5. 下面关于override说法正确的是 A.override的作用发生在运行时期 B.override修饰子类成员函数时编译时编译器会自动检测是否对基类中那个成员函数进行重写 C.override可以修饰基类的虚函数 D.override只能修饰子类的虚函数 6. 下面关于默认的构造函数说法正确的是 A.C98中用户可以选择让编译器生成或者不生成构造函数 B.在C11中即使用户定义了带参的构造函数也可以通过default让编译器生成默认的构造函数 C.delete的作用是删除new的资源别无它用 D.以下代码会编译通过 class A { public: A(){} A(int)delete; } 7. 下面关于lambda表达式说法错误的是 A.lambda表达式的捕获列表不能省略但可以使空 B.lambda表达式就是定义了一个函数 C.lambda表达式底层编译器是将其转化为仿函数进行处理的 D.[]{}是一个lambda表达式 8. 关于右值引用说法正确的是 A.引用是别名使用比指针更方便安全右值引用有点鸡肋 B.右值引用不能引用左值 C.右值引用只能引用右值 D.右值引用于引用一样都是别名 9. 关于引用和右值引用的区别说法正确的是 A.引用只能引用左值不能引用右值 B.右值引用只能引用右值不能引用左值 C.引用和右值引用都可以引用左值和右值 D.以上说法都不对 10. 下面关于右值引用作用说法错误的是 A.右值引用于引用一样只是一个别名别无它用 B.通过右值引用可以实现完美转发 C.通过右值引用可以将临时对象中的资源转移出去 D.通过右值引用可以实现移动构造函数提高程序运行效率 11. 下面关于列表初始化说法正确的是 A.C语言从C98开始就支持列表方式的初始化 B.列表初始化没有什么实际作用直接调用对应的构造函数就可以了 C.自定义类型可以支持多个对象初始化只需要增加initializer_list类型的构造函数即可 D.以下关于c和d的初始化结果完全相同 // short c 65535; short d { 65535 }; 答案及解析 1. C A正确只要是范围确定的都可以直接使用范围for B正确对于STL提供的容器采用范围for来进行遍历时编译器最后还是将范围for转化为迭代 器来访问元素的 C错误stack不需要遍历也没有提供迭代器因此不能使用范围for遍历 D正确因为范围for最终被编译器转化为迭代器来遍历的 E正确 2. D A正确C98中只能初始化数组C11中支持列表初始化才可以初始化容器 B正确C11对于new[]申请的空间可以直接初始化 C正确对于自定义类型需要提供initializer_listT类型的构造函数 D错误加和不加没有区别 3. B A正确 B错误C11中已经去除了auto声明自动类型变量的功能只可以用来进行变量类型推到 C正确因为函数在编译时还没有传递参数因此在编译时无法推演出形参的实际类型 D:正确auto仅仅只是占位符编译阶段编译器根据初始化表达式推演出实际类型之后会替换auto 4. D A正确 B错误C11中已经去除了auto声明自动类型变量的功能只可以用来进行变量类型推到 C正确因为函数在编译时还没有传递参数因此在编译时无法推演出形参的实际类型 D正确auto仅仅只是占位符编译阶段编译器根据初始化表达式推演出实际类型之后会替换auto 5. D Aoverride的作用时让编译器帮助用户检测是否派生类是否对基类总的某个虚函数进行重写如 果重写成功编译    通过否则编译失败因此其作用发生在编译时。 B错误修饰子类虚函数时编译时编译器会自动检测是否对基类中那个成员函数进行重写 C错误不能因为override主要是检测是否重写成功的而基类的虚函数不可能再去重写那个 类的虚函数 D正确 6. B A错误C98中用户不能选择用户如果没有定义构造函数编译器会生成默认的如果显式定义编译器将不再生成 B正确C11扩展了delete和default的用法可以用来控制默认成员函数的生成与不生成 C错误C11扩展了delete的用法可以让用户控制让编译器不生成默认的成员函数 D错误类定义结束后没有分号 7. B A正确捕获列表是编译器判断表达式是否为lambda的依据即使为空也不能省略 B错误lambda表达式不是一个函数在底层编译器将其转化为仿函数 C正确 D正确lambda表达式原型[捕获列表](参数列表)mutable-返回值类型{}  如果不需要捕获父作用域中内容时可以为空但是[]不能省略如果没有参数参数列表可以省略如果不需要改变捕获到父作用域中内容时mutable可以省略返回值类型也可以省略让编译器根据返回的结果进行推演但是{}不能省略因此[]{}是最简单的lambda表达式但是该lambda表达式没有任何意义 8. D A错误右值引用是C11中的一个重点可以实现移动语义、完美转发。 B错误一般右值引用只能引用右值如果需要引用左值时可以通过move函数转。 C错误同上。 D正确右值引用也是引用是别名。 9. C A错误T只能引用左值const T是万能引用左值和右值都可以引用。 B错误一般右值引用只能引用右值如果需要引用左值时可以通过move函数转。 C正确参考A和B的解析。 D错误。 10. A A错误右值引用是C11中的一个重点可以实现移动语义、完美转发 B正确实现完美转发时需要用到forward函数 C正确右值引用的一个主要作用就是实现移动语义以提高程序的效率 D正确 11. C A错误列表初始化是从C11才开始支持的 B错误列表初始化可以在定义变量时就直接给出初始化非常方便 C正确 D错误不同列表初始化在初始化时如果出现类型截断是会报警告或者错误的 本篇完。 下一篇C异常的使用异常体系优缺点​​​​​​​。
http://www.dnsts.com.cn/news/170202.html

相关文章:

  • 在家有电脑怎么做网站网页设计图片显示不出来怎么弄
  • 怎么做一元抢购网站桂林北站到象鼻山多远
  • 十一冶建设集团有限责任公司网站注册公司分类大全
  • 婚纱摄影网站设计论文域名已买 可以找其它人做网站吗
  • 深圳建网站有哪些公司蚌埠做网站
  • 重庆网站优化公司哪家便宜深圳前十设计公司
  • 济南网站建设方案聊城网站建设工作室
  • 网站开发的费用是怎么计算的wordpress屏蔽右键
  • 网站设计步骤的教学设计信息系统软件有哪些
  • 百度怎样建立网站四川 优质高职建设网站
  • 如何做好网站需求分析百度宁波运营中心
  • 网站建设使用工具wordpress菜单跳转页面
  • cms站群管理系统江汉建站公司
  • 有什么手机做网站的杭州网站推广与优化
  • 南宁网络企业网站淘宝客app开发
  • 网站开发 策划是干嘛的网站商城建站
  • 张槎网站开发网站界面设计的优点
  • 企业网站开发设计杭州网站制作方法
  • 做盗版电影网站赚钱手机版网站如何制作软件
  • 公司网站是怎么样的做网站和软件有区别吗
  • 网站建设 百度云wordpress选择菜单
  • 网站专题页是什么模板网站系统
  • 已经建网站做外贸湖南网站制作公司
  • 茶叶网站建站wordpress支付宝收银台
  • 网站制作价格行情新网站怎么做论坛推广
  • 做兼职的网站有哪些兰州新站点seo加盟
  • 做图字体网站wordpress 图片说明
  • 有edi证书可以做网站运营么手机网站导航栏如何做
  • 建立网站商城建议百度pc权重
  • 朗格手表网站寿光网站建设m0536