C++lambda详解~读书笔记
2014-10-06 23:54
225 查看
lambda表达式:
lambda表达式包含以下部分:
捕捉块(catpure block): 指定如何捕捉所在作用域中的变量,并供给lambda主体使用。
参数(parameter): (可选)lambda表达式使用的参数列表。只有在不使用任何参数,并且没有自定mutable、一个exception_specification 和一个return_type的情况下可以忽略该列表,返回类型在某些情况下也是可以忽略的,详见对return_type的说明:eg: [] {return 10;}
参数列表和普通函数的参数列表类似,区别如下:
参数不能有默认值。
不允许变长参数列表。
不允许未命名的参数。
mutable:(可选)如果所在作用域的变量是通过值捕捉到,那么lambda表达式主体中可以使用这些变量的副本。这些副本默认标记为const,因此lambda表达式的主体不能修改这些副本的值。如果lambda表达式标记为mutable,那么这些副本则不是const,因此主体可以修改这些本地副本。
exception_specification:(可选)用于指定lambda可以抛出的异常。
return_type:(可选)返回值的类型。如果忽略了return_type,那么编译器会根据以下原则判断返回类型:
如果lambda表达式主体的形式为{return expression;}那么表达式return_type的类型为expression的类型。
其他情况下的return_type为void。
下面的例子演示了如何创建一个lambda表达式并立即执行这个表达式。这行代码定义了一个没有返回值也没有任何参数的lambda表达式。
注意:尾部的(),这对括号使得这个lambda表达式立即执行:
根据前面的描述,这个例子中的返回值可以忽略:
还可以保存lambda表达式的指针,并且通过函数指针执行这个lambda表达式。使用C++11的auto关键字可以轻松地做到这一点:
捕捉块
lambda表达式的方括号部分称为lambda捕捉块(capture block),在这里可以指定如何从所在作用域中捕捉变量。捕捉变量的意思是可以在lambda表达式主体中使用这个变量。有两种方式:
[=]:通过值捕捉所有变量
[&]:通过引用捕捉所有变量
指定空白的捕捉块[]表示不从所在作用域中捕捉变量。还可以酌情决定捕捉那些变量以及这些变量的捕捉方法,方法是指定一个捕捉列表,其中带有可选的默认捕捉选项。前缀为&的变量通过引用捕捉。不带前缀的变量通过值捕捉。默认捕捉应该是捕捉列表中的第一个元素,可以是=或&。
例如:
[&x]只通过引用捕捉x,不捕捉其他变量。
[x]只通过值捕捉x,不捕捉其他变量。
[=, &x, &y]默认通过值捕捉,变量x和y例外,这两个变量通过引用捕捉。
[&, x]默认通过引用捕捉,变量x例外,这个变量通过引用捕捉。
[&x, &y]非法,因为标志符不允许重复。
通过引用捕捉变量的时候,一定保证党lambda表达式在执行的时候,这个引用还是可用的。
将lambda表达式用作返回值
定义在<functional>头文件中的std::function是多态的函数对象包装,类似函数指针。它可以绑定至任何可以被调用的对象(仿函数、成员函数指针、函数指针和lambda表达式),只要参数和返回类型符合包装的类型即可。返回一个double、接受两个整数参数的函数包装定义如下:
在这个例子中,lambda表达式的返回类型和空参数列表可以忽略,可改写为:
可以通过以下方式调用上述函数:
mutiplyBy2Lambda()示例通过值捕捉了变量x:[=]。假设这个函数重写为通过引用捕捉变量:[&],如下所示。根据代码所示。根据代码后面的解释,下面这段代码不能正常工作:
lambda表达式通过引用捕捉变量x。然而,lambda表达式会在程序后面执行,而不会在mutiplyBy2Lambda()函数的作用域中执行,在那里x的引用不再有效。
将lambda表达式用作参数:
您可以编写lambda表达式作为参数的函数。例如,可通过这种方式实现回调函数。下面的代码实现了一个testCallback()函数,这个函数接受一个整数vector和一个回调函数作为参数。这个实现迭代给定vector中的所有元素,并对每个元素调用回调函数,回调函数接受vector中每个元素作为int参数,并返回一个布尔值。如果回调函数返回false,那么停止迭代。
输出结果:
[capture_block](parameters) mutable exception_specification->return_type{ body }
lambda表达式包含以下部分:
捕捉块(catpure block): 指定如何捕捉所在作用域中的变量,并供给lambda主体使用。
参数(parameter): (可选)lambda表达式使用的参数列表。只有在不使用任何参数,并且没有自定mutable、一个exception_specification 和一个return_type的情况下可以忽略该列表,返回类型在某些情况下也是可以忽略的,详见对return_type的说明:eg: [] {return 10;}
参数列表和普通函数的参数列表类似,区别如下:
参数不能有默认值。
不允许变长参数列表。
不允许未命名的参数。
mutable:(可选)如果所在作用域的变量是通过值捕捉到,那么lambda表达式主体中可以使用这些变量的副本。这些副本默认标记为const,因此lambda表达式的主体不能修改这些副本的值。如果lambda表达式标记为mutable,那么这些副本则不是const,因此主体可以修改这些本地副本。
exception_specification:(可选)用于指定lambda可以抛出的异常。
return_type:(可选)返回值的类型。如果忽略了return_type,那么编译器会根据以下原则判断返回类型:
如果lambda表达式主体的形式为{return expression;}那么表达式return_type的类型为expression的类型。
其他情况下的return_type为void。
下面的例子演示了如何创建一个lambda表达式并立即执行这个表达式。这行代码定义了一个没有返回值也没有任何参数的lambda表达式。
注意:尾部的(),这对括号使得这个lambda表达式立即执行:
[] {cout << "Hello from Lambda" << endl; } ();
string result = [](const string & str) -> string { return "Hello from " + str; }("second Lambda"); cout << "Result: " << result << endl;输出如下:
Result: Hello from second Lambda
根据前面的描述,这个例子中的返回值可以忽略:
string result = [](const string & str){ return "Hello from " + str; }("second Lambda");
还可以保存lambda表达式的指针,并且通过函数指针执行这个lambda表达式。使用C++11的auto关键字可以轻松地做到这一点:
auto fn = [](const string& str) {return "hello from " + str; }; cout << fn("call 1") << endl; cout << fn("call 2") << endl;输出如下:
Hello from call 1 Hello from call 2
捕捉块
lambda表达式的方括号部分称为lambda捕捉块(capture block),在这里可以指定如何从所在作用域中捕捉变量。捕捉变量的意思是可以在lambda表达式主体中使用这个变量。有两种方式:
[=]:通过值捕捉所有变量
[&]:通过引用捕捉所有变量
指定空白的捕捉块[]表示不从所在作用域中捕捉变量。还可以酌情决定捕捉那些变量以及这些变量的捕捉方法,方法是指定一个捕捉列表,其中带有可选的默认捕捉选项。前缀为&的变量通过引用捕捉。不带前缀的变量通过值捕捉。默认捕捉应该是捕捉列表中的第一个元素,可以是=或&。
例如:
[&x]只通过引用捕捉x,不捕捉其他变量。
[x]只通过值捕捉x,不捕捉其他变量。
[=, &x, &y]默认通过值捕捉,变量x和y例外,这两个变量通过引用捕捉。
[&, x]默认通过引用捕捉,变量x例外,这个变量通过引用捕捉。
[&x, &y]非法,因为标志符不允许重复。
通过引用捕捉变量的时候,一定保证党lambda表达式在执行的时候,这个引用还是可用的。
将lambda表达式用作返回值
定义在<functional>头文件中的std::function是多态的函数对象包装,类似函数指针。它可以绑定至任何可以被调用的对象(仿函数、成员函数指针、函数指针和lambda表达式),只要参数和返回类型符合包装的类型即可。返回一个double、接受两个整数参数的函数包装定义如下:
function<double(int, int)> myWrapper;通过使用std::function,可从函数中返回lambda表达式,看一下定义:
function<int(void)> multiplyBy2Lambda(int x) { return [=]()->int{return 2 * x; }; }
在这个例子中,lambda表达式的返回类型和空参数列表可以忽略,可改写为:
function<int(void)> multiplyBy2Lambda(int x) { return[=] {return 2 * x; }; }这个函数的主体部分创建了一个lambda表达式,这个lambda表达式通过值捕捉所在作用域的变量,并返回一个整数,这个返回的整数是传给multiplyBy2Lambda()的值的两倍。这个multiplyBy2Lambda()函数的返回值类型为 function<int(void)>,即一个不接受参数并返回一个整数的函数。函数主体中定义的lambda表达式正好匹配这个原型。变量x通过值捕捉,因此,在lambda表达式从函数返回之前,x值的一份副本绑定至lambda表达式中的x。
可以通过以下方式调用上述函数:
function<int(void)> fn = mutiplyBy2Lambda(5); cout << fn() << endl;通过C++11的auto关键字可以简化这个调用:
auto fn = mutiplyBy2Lambda(5); cout << fn() << endl;输出为10。
mutiplyBy2Lambda()示例通过值捕捉了变量x:[=]。假设这个函数重写为通过引用捕捉变量:[&],如下所示。根据代码所示。根据代码后面的解释,下面这段代码不能正常工作:
function<int(void)> mutiplyBy2Lambda(int x) { return[&] {return 2 * x; }; }
lambda表达式通过引用捕捉变量x。然而,lambda表达式会在程序后面执行,而不会在mutiplyBy2Lambda()函数的作用域中执行,在那里x的引用不再有效。
将lambda表达式用作参数:
您可以编写lambda表达式作为参数的函数。例如,可通过这种方式实现回调函数。下面的代码实现了一个testCallback()函数,这个函数接受一个整数vector和一个回调函数作为参数。这个实现迭代给定vector中的所有元素,并对每个元素调用回调函数,回调函数接受vector中每个元素作为int参数,并返回一个布尔值。如果回调函数返回false,那么停止迭代。
void testCallback(const vector<int>& vec, const function<bool(int)>& callback) { for (auto i : vec) { if (!callback(i)) break; cout << i << " "; } cout << endl; }可以按照以下方式测试testCallback()函数。
vector<int> vec(10); int index = 0; generate(vec.begin(), vec.end(), [&index] {return ++index; }); for each (vec.begin(), vec.end()m[](int i) {cout << u << " "; }); { cout << endl; testCallback(vec, [](int i){return i < 6; }); }
输出结果:
1 2 3 4 5 6 7 8 9 10 1 2 3 4 5
相关文章推荐
- C++lambda详解~读书笔记
- C++lambda详解~读书笔记
- 匿名函数(lambda)详解 C++
- C++ lambda 表达式详解
- C++ Lambda 表达式使用详解
- 匿名函数(lambda)详解 C++
- (转)探索C++的秘密之一详解extern
- 使用Eclipse3.01 + MinGW3.1配置标准C/C++开发环境详解
- 探索C++详解extern "C"
- 【linux编程】C++内存管理详解(一)
- c++中const关键字使用详解
- 1.1.23. (C++ 语言命令详解(第二版))
- 【linux编程】C++内存管理详解(二)
- C/C++ 编码规范详解
- C++中的#pragma 预处理指令详解
- 踏入C++中的雷区——C++内存管理详解
- 《C++ Primer 3rd edition》读书笔记 - 第一篇 C++概述
- 《C++捷径教程》读书笔记--Chapter 2--C++概述
- 《The C++ programming language》读书笔记(1)——第一章:致读者
- c/c++程序之_KMP字符串模式匹配详解