• 【C++ Primer Chapter 10 总结】泛型算法


    头文件<algorithm>中的算法。
    不直接作用于容器,通过迭代器遍历容器元素。
    算法不会改变底下容器的大小,可以改变容器中元素的值。
     
    1.求和 
    int sum = accumulate(C.cbegin(), C.cend(), 0);           // 第三个参数表示sum = 0开始,C for Container
    string s = accumulate(C.cbegin(), C.cend(), string(""));    // 字符串拼接,调用string的+操作符   
    

      

    2.改变容器元素的值
    fill(C.befgin(), C.end(), value);
     
    int a1[] = {0,1,2,3,4,5,6,7,8,9};
    int a2[sizeof(a1) / sizeof(*a1)];
    auto ret = copy(begin(a1), end(a1), a2);  // ret返回a2数组最后一个元素的下一个元素
     
    replace(C.begin(), C.end(), src, target);
     
    3.排序算法
    用于序列容器!
    sort可以接受第三个参数,谓词。 谓词是一个可调用对象,它返回一个可以用作条件的值。 
    库算法使用的谓词要么是一元谓词(意味着它们有一个参数),要么是二元谓词(意味着它们有两个参数)。 
    接受谓词的算法在输入范围内的元素上调用给定谓词。 因此,必须能够将元素类型转换为谓词的参数类型。
    sort(C.begin(), C.end());
    stable_sort(C.begin(), C.end());                                // 维持字典序排序
    sort(C.begin(), C.end(), predicate);                            // 接受二进制谓词的sort版本使用给定的谓词代替<来比较元素。
     
    e.g.:
    vector<int> vec;
    bool self_defined_greater(int &a, int &b) { return a > b; }                   // 自定义函数
    struct greater {                                                                // 自定义比较类
        bool operator()(int &a, int &b) {                                           // 重载函数调用操作符
            return a > b;
        }
    }
    sort(vec.begin(), vec.end(), self_defined_greater);                   // 第三个参数是函数(指针)     
    sort(vec.begin(), vec.end(), greater());                              // 第三个参数是函数对象,可以通过“对象名+(参数列表)”的方式使用可以类似于函数功能。无命名的函数对象 (类名+(参数列表))
    sort(vec.begin(), vec.end(), [](int &a, int &b) { return a > b; });        // 第三个参数是lambda函数
    

      

     
    4.lambda表达式
    我们可以将任何类型的可调用对象传递给算法。
    如果可以对对象或表达式应用调用操作符(),那么该对象或表达式就是可调用的。(e.g.: expr是可调用的表达式,则expr(args)有效)。
    C++中的可调用对象有:函数,函数指针,重载了函数调用操作符的类类型的对象,lambda表达式。
    lambda表达式表示可调用的代码单元。它可以被认为是一个未命名的内联函数。
    [capture list] (parameter list) -> return type { function body }  
    // 捕获列表是在封闭函数中定义的局部变量列表(通常为空)
    // 形参列表 (为空的时候可以省略)
    // 尾置返回类型(可以省略,根据函数体返回语句推测出来,要求只能有一个return语句)
    // 函数体
     
    5.当我们定义一个lambda时,编译器会生成一个新的(未命名的)类类型,它对应于这个lambda。 
    当我们直接在函数中定义lambda函数时,定义了新类型和该类型的对象:实参是此编译器生成的类类型的未命名对象
    当使用auto来定义由lambda初始化的变量时,定义的是由该lambda生成的类型的对象。
    从lambda生成的类包含与lambda捕获的变量对应的数据成员。
    void fcn1()
    {
        int v1 = 42; // local variable
        auto f = [v1] { return v1; };  // f是lambda函数对应的类类型的对象   
        v1 = 0;
        auto j = f(); // j = 42; 捕获的变量的值在创建lambda时复制,而不是在调用时复制
    }
     
    6.lambda表达式的捕获列表。
    捕获列表仅用于局部非静态变量;lambda可以直接使用函数外部声明的局部静态和变量。
    • 按值捕获 [=]。捕获的变量的值在创建lambda时复制,而不是在调用时复制。
    • 按引用捕获 [&]。
    如果函数返回lambda,那么由于lambda捕获列表是对函数内变量(局部变量,函数结束后变量会被销毁)的捕获,lambda不能包含引用捕获。
    []                                             空列表
    [names]                                      逗号分割的列表
    [&]                                            封闭函数内的变量按引用的方式使用
    [=]                                            封闭函数内的变量按值的方式使用
    [&, identifier_list]                  identifier_list按值捕获,其余按引用捕获
    [=, identifier_list]                    identifier_list按引用捕获,其余按值捕获
     
    7.默认情况下,如果lambda主体包含除return以外的任何语句,则编译器推测该lambda返回void。
    transform(vi.begin(), vi.end(), vi.begin(), [](int i) { 
                                                    return i < 0 ? -i : i; 
                                                });   // return type是int
     
    transform(vi.begin(), vi.end(), vi.begin(), [](int i) { 
                                                    if (i < 0) return -i; else return i;
                                                });  // error: lambda包含多个语句,推测返回类型应该为void, 但是函数体有返回值,不匹配
     
    8.在多个需要相同操作的地方,应该用函数代替lambda表达式。
    使用函数作为参数的时候,调用函数的参数列表可能与可调用对象的参数列表不一致。
    可以使用库函数bind()生成带有新的参数列表的调用对象。 
    绑定函数可以被认为是一个通用函数的适配器。它接受一个可调用对象,并生成一个“适应”原始对象参数列表的新可调用对象。
    auto newCallable = bind(callable, arg_list);  // arg_list是一个以逗号分隔的参数列表,对应于给定可调用对象的参数
     
    bool check_size(const string &s, string::size_type sz) {
        return s.size() >= sz;
    }
    auto check6 = bind(check_size, _1, 6);    // _n是newCallable中的实参的占位符
    string s = "hello";
    bool b1 = check6(s);   // check6(s) 调用 check_size(s, 6)
     
    // sz 封闭函数内局部变量
    auto wc = find_if(words.begin(), words.end(), [sz](const string &a) {
        return a.size() >= sz;
    }
    auto wc = find_if(words.begin(), words.end(), bind(check_size, _1, sz));  // same
     
    auto g = bind(f, a, b, _2, c, _1);
    g(_1, _2)   // bind to f(a, b, _2, c, _1)
    g(X, Y)     // 调用 f(a, b, Y, c, X)
     
    auto g = bind(f, ref(a), b, _2, c, _1);   // ref(a) 引用方式传递
    

     

  • 相关阅读:
    Android_Spinner_example
    23.pyspider安装
    22.Windows及linux下gerapy使用
    21.scrapy爬虫部署
    12.利用kakatips对网站数据信息监控
    11.启信宝数据二次筛选解密(字符串的分割与拼接及正则匹配)-2
    10.Ubuntu操作系统及python2.7、3.5 exe
    9.数据库多表一起查询
    8.代理ip使用
    7.阿布云代理服务器试用
  • 原文地址:https://www.cnblogs.com/tristatl/p/14825272.html
Copyright © 2020-2023  润新知