• 【C++11重点语法上】lambda表达式,初始化列表


    目录

    引子:C++11为什么的源来

    语法1:初始化列表 

            1.2.2 多个对象的列表初始化

    语法3:默认成员函数控制(delete,default)

    语法4:lambda表达式 


    引子:C++11为什么的源来

    在2003年C++标准委员会曾经提交了一份技术勘误表(简称TC1),使得C++03这个名字已经取代了C++98称为 C++11之前的最新C++标准名称。打算5年一个标准,打算07年出一个新标准,但是没有完成,把C++07改名叫C++0x,直到11年完成改名问C++11;相比于C++98/03,C++11则带来了数量可观的变化,其中包含了约140个新特性,以及对C++03标准中约600个缺陷的修正,有很多新东西,其中也有许多鸡肋语法;C++11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅功能更强大,而且能提升程序员的开发效率

    语法1:初始化列表 

    1.1内置类型的初始化列表

    • 可以省略‘=’
    1. int main()
    2. {
    3. // 内置类型变量
    4. int x1 = {10};
    5. int x2{10};
    6. int x3 = 1+2;
    7. int x4 = {1+2};
    8. int x5{1+2};
    9. // 数组
    10. int arr1[5] {1,2,3,4,5};
    11. int arr2[]{1,2,3,4,5};
    12. // 动态数组,在C++98中不支持
    13. int* arr3 = new int[5]{1,2,3,4,5};
    14. // 标准容器
    15. vector<int> v{1,2,3,4,5};
    16. map<int, int> m{{1,1}, {2,2,},{3,3},{4,4}};
    17. return 0;
    18. }

     1.2自定义类型的列表初始化

    1.2.1. 标准库支持单个对象的列表初始化

    • 多参数构造函数,支持隐式类型转换
    1. class Point
    2. {
    3. public:
    4. Point(int x = 0, int y = 0): _x(x), _y(y)
    5. {}
    6. private:
    7. int _x;
    8. int _y;
    9. };
    10. int main()
    11. {
    12. Pointer p{ 1, 2 };
    13. return 0;
    14. }

    1.2.2 多个对象的列表初始化

    C++98支持数组使用列表初始化 ,C++98不支持构造函数列表初始化  

    1. int array1[] = {1,2,3,4,5};
    2. int array2[5] = {0};

    C++支持构造函数列表初始化  

    vector<int> v{1,2,3,4,5};
    

    原因:1,2,3,4,5,先隐式构造为initializer_list的一个对象,再调用vector对应的构造函数

    容器vector的 initializer_list 构造函数和赋值运算符重载

    • initializer_list是系统自定义的类模板,该类接口函数:迭代器 :begin()、end()以及获取区间中元素个数的方法size()
    • 多个对象想要支持列表初始化,需给该类(模板类)添加一个带有initializer_list类型参数的构造函数;
    1. Vector(initializer_list l)
    2. : _capacity(l.size())
    3. , _size(0)
    4. {
    5. _array = new T[_capacity];
    6. for (auto e : l)
    7. _array[_size++] = e;
    8. }
    9. Vector& operator=(initializer_list l)
    10. {
    11. delete[] _array;
    12. size_t i = 0;
    13. for (auto e : l)
    14. _array[i++] = e;
    15. return *this;
    16. }

     C++11扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型(vector,list)和用户自定义的类型,使用初始化列表时,可添加等号(=),也可不添加。 

    语法2:decltype类型推导

    • 不知道对象或者返回值的类型,decltype是根据表达式的实际类型推演出定义变量时所用的类型
    1. const int x = 2;
    2. const int y = 3;
    3. decltype(x+y) z = 3;
    4. cout << typeid(z).name() << endl;

     语法3:默认成员函数控制(delete,default)

    1.default:显式缺省函数 

    • 默认成员函数都可以使用default

    写了拷贝构造函数就不会默认生成构造函数了,就没办法创造一个无参的对象了 

    1. class Person
    2. {
    3. public:
    4. //person()=default;
    5. Person(const char* name,int age)
    6. :_name(name)
    7. ,_age(age)
    8. {}
    9. private:
    10. string _name;
    11. int _age=0;
    12. };
    13. int main()
    14. {
    15. Person p;
    16. return 0;
    17. }

    person()=default ;这句代码就可以让编译器默认生成;

    2.delete:删除默认函数,没有办法真正删除,只是不让删除使用

    C++98 防拷贝:1、只声明不实现 2、声明成私有 

    1. class A
    2. {
    3. public:
    4. A() = default;
    5. private:
    6. A(const A& a);
    7. };
    1. 只声明不实现 ,调用也不会发生改变
    2.  声明成私有,防止在类外被声明

     C++11:使用A(const A& a)=delete即可

    1. class A
    2. {
    3. public:
    4. A() = default;
    5. A(const A& a)=delete;
    6. private:
    7. };

    语法4:lambda表达式 

    这里有一组数据,按名称或者按数量,要怎么办了;

    pairint> fruit[] = { {"香蕉",15}, {"菠萝",23},{"柿子",35}, {"芒果",12} };

    使用仿函数 

    1. class compareName
    2. {
    3. public:
    4. bool operator()(const pairint>& l, const pairint>& r)
    5. {
    6. return l.first <= r.first;
    7. }
    8. };
    9. class compareNumber
    10. {
    11. public:
    12. bool operator()(const pairint>& l, const pairint>& r)
    13. {
    14. return l.second <= r.second;
    15. }
    16. };
    17. int main()
    18. {
    19. pairint> fruit[] = { {"香蕉",15}, {"菠萝",23},{"柿子",35}, {"芒果",12} };
    20. sort(fruit, fruit+ 4, compareNumber());
    21. for (int i = 0; i < 4; i++)
    22. {
    23. cout << fruit[i].second << " ";
    24. }
    25. cout << endl;
    26. sort(fruit, fruit + 4, compareName());
    27. for (int i = 0; i < 4; i++)
    28. {
    29. cout << fruit[i].first << " ";
    30. }
    31. }

    每次为了实现一个algorithm算法, 都要重新去写一个类,如果每次比较的逻辑不一样,还要去实现多个类,特别是相同类的命名,这些都给编程者带来了极大的不便;

    使用lambda表达式代码就会简短一些

    1. pairint> fruit[] = { {"香蕉",15}, {"菠萝",23},{"柿子",35}, {"芒果",12} };
    2. //数量比较
    3. sort(fruit, fruit + 4, [](const pairint>& l, const pairint>& r)->bool
    4. { return l.second <= r.second; });
    5. for (int i = 0; i < 4; i++)
    6. {
    7. cout << fruit[i].second << " ";
    8. }
    9. cout << endl;
    10. //名字比较
    11. sort(fruit, fruit + 4, [](const pairint>& l, const pairint>& r)->bool
    12. { return l.first <= r.first;});
    13. for (int i = 0; i < 4; i++)
    14. {
    15. cout << fruit[i].first << " ";
    16. }

    lambda表达式结构 

    lambda表达式语法:

    1. 参数列表。与普通函数的参数列表一致,如果不需要参数传递,则可以连同()一起省略 
    2. mutable:默认情况下,lambda函数捕捉的是一个const变量,mutable可以取消其常量性使用该修饰符时,参数列表不可省略(即使参数为空),
    3. ->返回值:返回值类型。用追踪返回类型形式声明函数的返回值类型,没有返回值时此部分可省略返回值类型明确情况下,也可省略,由编译器对返回类型进行推导
    4. 函数体:在该函数体内,除了可以使用其参数外,还可以使用所有捕获到的变量

     最简单的一个lambda表达式:[]{};

    捕捉列表:该列表总是出现在lambda函数的开始位置,编译器根据[]来判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文中的变量供lambda函数使用。

    1. int a = 10;
    2. int b = 20;
    3. auto Add = [a, b] {return a + b; };
    4. cout<<Add();

    输出:30; 

    5种捕捉:所有捕捉的变量都是被const修饰的;加mutable就取消了常性

    • [var]:表示  值传递方式捕捉变量;例int a=10;int b=20;[a,b]{return a+b;};
    • [=]:表示  值传递方式捕获所有父作用域中的变量(包括this)例int a=10;int b=20;[=]{return a+b;};
    • [&var]:表示  引用传递捕捉变量var;例int a=10;int b=20;[&a,&b]{int tmp=a;a=b;b=tem;     return a+b;};(引用才可以交换,值传递(拷贝)不可以交换)
    • [&]:表示  引用传递捕捉所有父作用域中的变量(包括this)
    • [this]:表示  值传递方式捕捉当前的this指针

    实际在底层编译器对于lambda表达式的处理方式,完全就是按照函数对象的方式处理的,只是简短仿函数的写法;

  • 相关阅读:
    web渗透之信息收集【完整版】
    【愚公系列】2022年07月 python界面可视化 VS2022配置PyQt5环境
    react 使用 craco库 配置 @ 路径,以及 jsconfig.json或者tsconfig.json 配置智能提示
    【校招VIP】【约起来】产品PRD文档:重点在于能约起来的类别
    (附源码)ssm基于jsp高校选课系统 毕业设计 291627
    南大通用GBase8s 常用SQL语句(289)
    浅谈为什么多态只能是指针或引用
    掌握数据仓库建模和元数据备份的方法
    Octave安装
    PHP代码审计入门-DVWA靶场暴力破解篇
  • 原文地址:https://blog.csdn.net/m0_72964546/article/details/128099093