zoukankan      html  css  js  c++  java
  • lambda及参数绑定

    一、介绍

      对于STL中的算法,我们都可以传递任何类别的可调用对象。对于一个对象或一个表达式,如果可以对其使用调用运算符,则称它为可调用的。即,如果e是一个可调用的表达式,则我们可以编写代码e(args),其中args是一个逗号分隔的一个或多个参数的列表。

      一般来说,有四种可调用对象:函数,函数指针,重载了函数调用运算符的类,以及lambda表达式。

    二、lambda表达式

    1. 概述

      一个lambda表达式表示一个可调用的代码单元。我们可以将其理解为一个未命名的内联函数。与任何函数类似,一个lambda具有一个返回类型、一个参数列表和一个函数体。但与函数不同,lambda可能定义在函数内部。

      一个lambda的通用表达式为:

        [capture list] (parameter list) -> return type { function body }
    

      举个简单的例子:

    auto f = [] { return 42; };
    cout << f() << endl; //打印42
    

    注意,忽略括号和参数列表相当于指定了空的参数列表。如果函数体为一条return语句,lambda将根据代码推断返回类型,否则类型为void。

    2. 传递参数

      如函数一样,lambda表达式也可以传递参数,但是不同的是,其不能有默认参数。一个lambda调用的实参数目永远要和形参数目相等。

      举个例子:

    auto f = [](const string &lhs, const string &rhs) 
        { return a.size() < b.size(); };
    

    3. 使用捕获列表

      所谓捕获列表,则是中括号中的参数,表示使用其所在函数中的任何局部变量。捕获的方式有三种:值捕获引用捕获隐式捕获

    /*
     * 采用值捕获的前提是,变量可以拷贝,
     * 被捕获的变量是在创建时拷贝,而非在调用是拷贝。
     */
    void fcn1() {
        size_t v1 = 42;
        auto f = [v1] { return v1; };
        v1 = 0;
        cout << f() << endl; //打印42
    }
    
    /*
     * 若想要改变捕获列表中的值,
     * 可以采用引用捕获,
     * 引用捕获保存的是引用。
     */
    void fcn2() {
        size_t v1 = 42;
        auto f = [&v1] { return v1; };
        v1 = 0;
        cout << f() << endl; //打印0
    }
    
    /*
     * 隐式捕获可以让编译器根据lambda体中的代码来推断我们要使用哪些变量;
     * 在捕获列表中。
     * &表示采用引用捕获方式,
     * =则表示采用值捕获方式。
     */
     void biggies(vector<string> &words, 
        vector<string>::size_type sz, 
        ostream &os = cout, 
        char c = ' ') 
    {
        //采用引用捕获
        for_each(words.begin(), words.end(),
            [&](const string &s) { os << s << c; });
        //os显示捕获,采用引用捕获方式;其他(c)为值捕获
        for_each(words.begin(), words.end(),
            [=, &os](const string &s) { os << s << c; });
    }
    

    4. 指定返回类型

      如前面所提到,如果一个lambda体包含return之外的任何语句,则编译器假定此lambda返回void。

    //错误示范:编译器推断为void,实际为int
    auto f = [](int i) { if(i < 0) return -i; else return i; };
    
    //可以修改为如下
    auto f = [](int i) -> int { if(i < 0) return -i; else return i; };
    

    三、参数绑定

      所谓的参数绑定,其实使用bind函数实现的,其定义在functional中。可以将bind函数看作一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象。

      一般的表示形式为:

        auto newCallable = bind(callable, arg_list);
    

      callable本身是一个可调用对象,arg_list是一个逗号分隔的参数列表,对应给定的callable的参数。

      arg_list中的参数可能包含如_n的名字,其定义在名叫placeholders的命名空间中,而这个命名空间本身定义在std命名空间中。_n为占位符。

      举个简单的例子:

    bool check_size(const string &os, string::size_type sz) {
        return s.size() > sz;
    }
    auto check6 = bind(check_size, _1, 6);
    stirng s = "hello";
    bool b1 = check6(s);
    

      为了与不支持拷贝的参数绑定,bind经常和ref一起用,ref也定义在头文件functional中,作用是返回一个引用对象。

    ostream &print(ostream &os, const string &s, char c) {
        return os << s << c;
    }
    //错误示范
    for_each(words.begin(), words.end(), bind(print, os, _1, ' '));
    //正确示范
    for_each(words.begin(), words.end(), bind(print, ref(os), _1, ' '));
    
  • 相关阅读:
    程序员装逼指南(网上看到的,笑喷了……)
    【转】Flex4 中skinclass使用Path绘制多边形
    批处理根据星期自动备份到服务器的相应文件夹
    精妙Sql语句备忘
    The project file ' ' has been renamed or is no longer in the solution. 解决方案
    HttpPostedFileBase always null when upload file by asp.net mvc4 mobile
    解决.net绘制的 WinForm 在 windows7下变形的方法
    select语句中,直接为选出的数据添加uniqueidentifier字段
    向各位请教一个关于Decorator模式的问题
    子查询基础知识
  • 原文地址:https://www.cnblogs.com/vachester/p/7715621.html
Copyright © 2011-2022 走看看