zoukankan      html  css  js  c++  java
  • C++ lambda表达式

    lambda表达式简介

    lambda表达式是C++11新特性(C++11 特性),用于创建一个可调用单元,可理解成匿名内联函数。

    可调用单元 是指什么?
    可调用单元通常是指可调用对象(或函数)。

    可调用对象

    一个对象或表达式,如果可对其使用可调用运算符("()"),则称这个对象或表达式为可调用对象。

    可调用对象组成
    4种:函数, 函数指针, 重载了"()"的类,lambda表达式。
    本文主要介绍lambda表达式。

    [======]

    lambda表达式语法

    格式

    [捕获列表](参数列表) mutable或exception -> 返回值类型 { 函数体 }
    

    捕获列表

    捕获列表可以为空,但"[]"不可用省略,用来标识一个lambda表达式开始。
    lambda要访问所在函数的局部变量时,必须先捕获。2种局部变量捕获方式:

    • 值捕获:创建lambda表达式时,拷贝所在函数的局部变量的值。
    • 引用捕获:创建lambda表达式时,获取变量的引用。需要确保lambda使用变量时,变量对应对象存在。

    注意:
    1)值捕获是发生在lambda创建时,而非调用时。
    2)lambda无法捕获任何static变量、全局变量,不过可以在lambda表达式内部直接访问。

    // 值捕获拷贝变量,发生在lambda创建时
    void func1()
    {
    	size_t v1 = 10;
    	auto a = [v1]()->int { return v1; }; // 值捕获v1 = 10
    	v1 = 0;
    	auto b = a(); // lambda调用时,不会改变捕获值,因此b为10
    }
    
    // 引用捕获获取变量引用
    void func2()
    {
    	size_t v1 = 10;
    	auto a = [&v1]()->int { return v1; }; // 引用捕获v1
    	v1 = 0;
    	auto b = a(); // b为0
    }
    
    // lambda访问全局变量、static变量
    size_t sz = 10;
    static int counter = 0;
    void func3()
    {
    	auto f0 = [sz](int a, int b) { return a > b}; // 错误:lambda无法捕获任何具有静态存储持续时间的变量
    	auto f = [](string& x, string& y)->bool {
    		counter++; // OK:lambda表达式可以直接访问static变量
    
    		if (x.size() > sz) { // OK:lambda表达式可以直接访问global变量
    			return true;
    		}
    		return x > y; 
    	};
    
    	string s1 = "123456";
    	string s2 = "abcdefgh";
    	auto r = f(s1, s2);
    
    	cout << r << endl; // 打印0
    	cout << counter << endl; // 打印1
    }
    

    隐式捕获

    捕获列表中写“&”,告诉编译器采用引用捕获方式;写“=”,告诉编译器采用值捕获方式。如果有个别局部变量不需要用统一的捕获方式,可以专门指出其捕获方式,然后用逗号方式分隔不同捕获。

    string v1 = "abc";
    string v2 = "123465";
    string v3 = "qwert";
    
    auto f1 = [&](const string& s)->{ cout << v1.size() + s.size() << endl; }; // 引用捕获
    auto f2 = [=](const string& s)->{ cout << v2.size() + s.size() << endl; }; // 值捕获
    auto f3 = [=, &v1](const string& s)->{ cout << v2.size() + s.size() << endl; }; // 引用捕获v1, 其余都是值捕获
    auto f4 = [&, v2, v3](const string& s)->{ cout << v2.size() + s.size() << endl; }; // 值捕获v2, v3, 其余都是引用捕获
    f1("test1");
    f2("test2");
    f3("test3");
    

    参数列表

    参数列表 可以为空,但"()"不可用省略。类似于函数定义。

    mutable关键字

    • mutable对于const函数作用
      const成员函数中,通常不能修改non-static数据成员。如果要修改,需要将数据成员声明为mutable,表示该变量可变,不再有constness(常量性)约束。
      具体可参见Effective C++ 条款03:尽可能使用const

    • mutable对于lambda作用
      在lambda表达式中,mutable有类似效果,默认不能修改值捕获的变量。
      当lambda要修改值捕获的变量时,必须添加mutable声明。

    void fcn()
    {
    	size_t v1 = 10;
    	auto f = [v1]() mutable { return ++v1; }; // 加上mutable才能修改值捕获的v1
    	// <=> auto f = [v1]() mutable -> int { return ++v1; }; 
    	v1 = 0;
    	auto j = f(); // j 为11
    }
    

    指定lambda返回类型

    默认情况下,
    1)如果lambda函数体只包含单一return语句,可以省略lambda返回类型(编译器自动推断返回类型)。
    2)如果包含return之外的任何语句,编译器假定此lambda返回void。

    简单来说,如果编译器无法推断lambda返回类型,就需要尾置返回类型,不可省略。

    例,

    vector<int> vec;
    ... // vec插入数据
    	
    // OK, 单一return语句, 编译器能推断出lambda的返回类型
    transform(vec.begin(), vec.end(), vec.begin(), [](int i) { return i < 0 ? -i : i; }); 
    
    // 错误, 不能推断lambda的返回类型
    transform(vec.begin(), vec.end(), vec.begin(), [](int i) -> int { 
    	/* 非单一return语句 */
    	if (i < 0) return -i; 
    	else return i;
    });
    
  • 相关阅读:
    黄聪:Wordpress写文章自动过滤HTML标签解决方法
    黄聪:C#中调用python脚本语言
    黄聪:DIV+CSS建站经验总结,不同版本IE下CSS布局bug问题(IE5、IE6、IE7、IE8、火狐Firefox兼容)
    黄聪:Python下安装Mysqldb出现DeprecationWarning: the sets module is deprecated from sets错误解决方案
    黄聪:Wordpress数据库中各个表的用途描述
    黄聪:Python实现Discuz论坛的自动POST登录发贴回帖(转)
    黄聪:python访问抓取网页常用命令(保存图片到本地、模拟POST、GET、中文编码问题)
    黄聪:jquery对ajax的error内的XMLHttpRequest返回的exception获取里面的信息
    黄聪:XML操作中常用的XPath表达式
    黄聪:Python初始化系统变量设置
  • 原文地址:https://www.cnblogs.com/fortunely/p/15417012.html
Copyright © 2011-2022 走看看