C++11中lambda表达式的基本语法格式为:

[capture](parameters) -> return_type { /* ... */ }

  其中 [] 内为外部变量的传递方式:

[]        //no variables defined. Attempting to use any external variables in the lambda is an error.
[x, &y] //x is captured by value, y is captured by reference
[&] //any external variable is implicitly captured by reference if used
[=] //any external variable is implicitly captured by value if used
[&, x] //x is explicitly captured by value. Other variables will be captured by reference
[=, &z] //z is explicitly captured by reference. Other variables will be captured by value

  () 内为参数,比如:

[](int x, int y) -> int { return x + y; }

  return_type就是字面上的意思,也就是返回类型或者说函数类型。{}内则是我们编写的函数要执行的功能代码。

  我们知道,要执行函数则需要调用函数名,但匿名函数没有函数名(匿名函数最大的好处就是以后定义函数不用再纠结给函数命什么名了),因而突然间拿到一个lambda表达式,我们会突然间有点迷惑,不知道该怎么样执行它。

  下面代码则给了几个调用并执行匿名函数的方式:

#include <iostream>
#include <vector>
#include <string>
#include <functional> /** function */
#include <algorithm> /** for_each */ /** 建立一个类似创建线程函数的用法的函数来完成执行匿名函数 */
int my_eval(std::function <int(int, int)> f, int x, int y) {
return f(x, y);
} int main() {
/**用法1: 通过将匿名函数存储在变量中,并作为参数传递*/
std::function<int(int, int)> f0 = [](int x, int y) -> int {return x + y; };//lambda 表达式
auto f1 = [](int x, int y) -> int {return x * y; };//没有使用任何外部变量
std::cout << "f0: " << my_eval(f0, 3, 4) << std::endl;
std::cout << "f1: " << my_eval(f1, 2, 3) << std::endl; /**用法2: 保存到vector中*/
std::vector<decltype(f0)> func_s{ f0, f1 };
func_s.push_back([](int x, int y) {return x - y; });
for (auto f : func_s)//遍历匿名函数
std::cout << "f: " << f(3, 1) << std::endl; /**用法3: 使用for_each传入匿名函数*/
std::vector<int> nums{ 1,2,3,4,5 };
int sum = 0; //代码中使用了sum 因而通过[&]引用隐式捕获,如果代码没有使用任何外部变量,则不传递参数
std::for_each(begin(nums), end(nums), [&](int x) {sum += x; });
//x为遍历nums传递的值
std::cout << "f3: " << sum << std::endl; //同上用法 但匿名函数参数有不同的地方
std::string str{ "hello world" };
std::string s = "";
std::string c = " "; //指明外部变量s通过引用捕获,c通过传递值捕获
std::for_each(begin(str), end(str), [&s, c](char x) {s += (x + c); }); std::cout << "f4: " << s << std::endl; /**用法4: 保存到函数指针*/
auto my_lambda_func = [](int x) {std::cout << "f5: " << x << std::endl;};
void(*func_ptr)(int) = my_lambda_func;//注意变量名不能与函数指针名冲突
func_ptr(4);//回调
/**或者直接这样写:
* void(*func_ptr)(int) = [](int x) {std::cout << "f5: " << x << std::endl;};
* func_ptr(4);
*/ /**用法5: 直接存储在auto类型变量中,然后调用*/
auto myfunc = [](int x) {std::cout << "f6: " << x << std::endl;};
myfunc(5); return 0;
}

  运行结果:

f0: 7
f1: 6
f: 4
f: 3
f: 2
f3: 15
f4: h e l l o w o r l d
f5: 4
f6: 5

------------------update 2018-02-15 02:20:50---------------

  前面测试了几个用法,但却不够细节,今天再来补充一些细节。

  实际上,代码中有几个值得探究的地方:

//重新举两个例子:
auto func = [](std::string params) {return params;};
auto func = [](std::string params) -> std::string {return params;};

  上面两个lambda表达式不同的地方就是一个有写明返回类型,一个没有。

  而这两种写法都可以正确进行,但前提是必须使用auto类型让编译器自己判断返回类型,否则就会报错:

  使用正确类型变量:

#include <iostream>
#include <string> int main()
{
std::string func = [](std::string params) {return params;};
std::cout << func("hello world!"); return 0;
}

  报错:

error: conversion from 'main()::<lambda(std::__cxx11::string)>' to non-scalar type 'std::__cxx11::string {aka std::__cxx11::basic_string<char>}' requested|

  使用错误类型变量:

#include <iostream>
#include <string> int main()
{
int func = [](std::string params) {return params;};
std::cout << func("hello world!"); return 0;
}

  报错:

main.cpp||In function 'int main()':|
main.cpp|6|error: invalid user-defined conversion from 'main()::<lambda(std::__cxx11::string)>' to 'int' [-fpermissive]|
main.cpp|6|note: candidate is: main()::<lambda(std::__cxx11::string)>::operator std::__cxx11::string (*)(std::__cxx11::string)() const <near match>|
main.cpp|6|note: no known conversion from 'std::__cxx11::string (*)(std::__cxx11::string) {aka std::__cxx11::basic_string<char> (*)(std::__cxx11::basic_string<char>)}' to 'int'|
main.cpp|7|error: 'func' cannot be used as a function|
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

  那如果这样呢:

#include <iostream>
#include <string> int main()
{
int func = [](std::string params) -> int {return params;};
std::cout << func("hello world!"); return 0;
}

  报错:

main.cpp|6|error: cannot convert 'std::__cxx11::string {aka std::__cxx11::basic_string<char>}' to 'int' in return|
main.cpp||In function 'int main()':|
main.cpp|6|error: invalid user-defined conversion from 'main()::<lambda(std::__cxx11::string)>' to 'int' [-fpermissive]|
main.cpp|6|note: candidate is: main()::<lambda(std::__cxx11::string)>::operator int (*)(std::__cxx11::string)() const <near match>|
main.cpp|6|note: no known conversion from 'int (*)(std::__cxx11::string) {aka int (*)(std::__cxx11::basic_string<char>)}' to 'int'|
main.cpp|7|error: 'func' cannot be used as a function|
||=== Build failed: 3 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

  这样呢:

#include <iostream>
#include <string> int main()
{
std::string func = [](std::string params) -> std::string {return params;};
std::cout << func("hello world!"); return 0;
}

  然后会发现竟然也报错了:

main.cpp||In function 'int main()':|
main.cpp|6|error: conversion from 'main()::<lambda(std::__cxx11::string)>' to non-scalar type 'std::__cxx11::string {aka std::__cxx11::basic_string<char>}' requested|
main.cpp|7|error: no match for call to '(std::__cxx11::string {aka std::__cxx11::basic_string<char>}) (const char [13])'|
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

  说是从<lambda(std::__cxx11::string)>转换为非标量类型??不太明白。

  然后试试这样:

#include <iostream>
#include <string> int main()
{
char* func = [](char* params) -> char* {return params;};
std::cout << func("hello world!"); return 0;
}

  报错:

main.cpp||In function 'int main()':|
main.cpp|7|error: cannot convert 'main()::<lambda(char*)>' to 'char*' in initialization|
main.cpp|8|error: 'func' cannot be used as a function|
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

  就是说不能在初始化过程中对lambda进行转换。

  然后再试试这样:

#include <iostream>
#include <string> int main()
{
std::string (*func)(std::string) = [](std::string params) {return params;};
std::cout << func("hello world!"); return 0;
}

  这个代码能正常显示结果,但最开始运行了几次会在显示结果后崩溃...不知道为什么,然后后面运行就正常了,但显示完结果后会感觉很明显的停顿一下才显示Press any key to continue.

  这样写就能正常显示,且没有停顿:

#include <iostream>
#include <string> int main()
{
void(*func)(std::string) = [](std::string params) {std::cout << params;};
func("hello world!"); return 0;
}

  emmm...

  从这几个测试可以看出,貌似编译器处理lambda表达式的时候,不能直接将匿名函数赋值给一个具有基本类型的变量,这个过程原理是什么还不太明白。但可以直接赋给一个函数指针,然后调用。

  但需要注意:函数指针必须带有类型,不能用auto,因为程序无法推断回调函数的类型。比如:

#include <iostream>
#include <string> int main()
{
auto(*func)(std::string) = [](std::string params) {std::cout << params;};
func("hello world!"); return 0;
}

  所以,可见使用auto自动判断类型是一个很简便的写法,但也需要正确使用:

#include <iostream>
#include <string> int main()
{
auto func = [](std::string params) {std::cout << params;};
func("hello world!"); return 0;
}

  总结一下:

  匿名函数可以不用写返回的类型也就是:

 -> return_type

  完全可以省略掉。然后可以存储在正确类型的函数指针或auto类型的变量中进行调用。

--------------------------------------

  参考资料:

    维基百科-C++ 11

C++11 — lambda表达式(匿名函数)的更多相关文章

  1. [二] java8 函数式接口详解 函数接口详解 lambda表达式 匿名函数 方法引用使用含义 函数式接口实例 如何定义函数式接口

    函数式接口详细定义 package java.lang; import java.lang.annotation.*; /** * An informative annotation type use ...

  2. java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口

    函数式接口详细定义 函数式接口只有一个抽象方法 由于default方法有一个实现,所以他们不是抽象的. 如果一个接口定义了一个抽象方法,而他恰好覆盖了Object的public方法,仍旧不算做接口的抽 ...

  3. Python:lambda表达式(匿名函数)

    lambda表达式: 通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数. 当我们在传入函数时,有些时候,不需要显式地定义函数,直接传入匿名函数更方便. 在Python中 ...

  4. lambda表达式 匿名函数

    lambda函数是一种快速定义单行最小函数的方法,是从Lisp借鉴而来的,可以用在任何需要函数的地方. 基础 lambda语句中,冒号前是参数,可以有多个,用逗号分割:冒号右边是返回值. lambda ...

  5. lambda表达式匿名函数

    匿名函数是一个“内联”语句或表达式,可在需要委托类型的任何地方使用.可以使用匿名函数来初始化命名委托,或传递命名委托(而不是命名委托类型)作为方法参数. C# 中委托的发展 在 C# 1.0 中,您通 ...

  6. C++中对C的扩展学习新增语法——lambda 表达式(匿名函数)

    1.匿名函数基础语法.调用.保存 1.auto lambda类型 2.函数指针来保存注意点:[]只能为空,不能写东西 3.std::function来保存 2.匿名函数捕捉外部变量(值方式.引用方式) ...

  7. C++11 lambda 表达式

    C++11 新增了很多特性,lambda 表达式是其中之一,如果你想了解的 C++11 完整特性,建议去这里,这里,这里,还有这里看看.本文作为 5 月的最后一篇博客,将介绍 C++11 的 lamb ...

  8. C++11 lambda 表达式解析

    C++11 新增了很多特性,lambda 表达式是其中之一,如果你想了解的 C++11 完整特性,建议去这里,这里,这里,还有这里看看.本文作为 5 月的最后一篇博客,将介绍 C++11 的 lamb ...

  9. 【C++】C++中的lambda表达式和函数对象

    目录结构: contents structure [-] lambda表达式 lambda c++14新特性 lambda捕捉表达式 泛型lambda表达式 函数对象 函数适配器 绑定器(binder ...

  10. 详解 C++11 lambda表达式

    详解 C++11 lambda表达式   lambda表达式是函数式编程的基础.咱对于函数式编程也没有足够的理解,因此这里不敢胡言乱语,有兴趣的可以自己查找相关资料看下.这里只是介绍C++11中的la ...

随机推荐

  1. 如何使用git和github

    转载:https://www.cnblogs.com/cxscode/p/8325064.html 如何用git将项目代码上传到github 先上常用语句 git add . git commit - ...

  2. 初识HttpRunner

    一.背景 前段时间接触到HttpRunner自动化测试框架,发现对测试人员代码能力要求极低,用户只需准备好用例脚本即可发起测试,非常方便,故记录一下. 二.安装 运行环境 HttpRunner框架基于 ...

  3. B站上线互动视频背后,是一场谁都输不起的未来之战

    毋庸置疑的是,视频网站的竞争已愈发激烈.而它们的竞争体现在多个维度,比如买视频会员赠送购物网站会员.依靠各自的社交体系不断尝试打破圈层瓶颈等.当然,最直接的竞争还是体现在内容层面.购买独家版权.制作原 ...

  4. 「JSOI2015」字符串树

    「JSOI2015」字符串树 传送门 显然可以树上差分. 我们对于树上每一条从根出发的路径都开一 棵 \(\text{Trie}\) 树,那么我们就只需要在 \(\text{Trie}\) 树中插入一 ...

  5. December 28th, Week 52nd Saturday, 2019

    If you start at the bottom, pay your dues, life here can be a dream come true. 只要你从头开始,脚踏实地,梦想是可以成真的 ...

  6. 【代码审计】VAuditDemo 文件包含漏洞

    在 index.php中先判断get过来的module是否设置了变量,如果已经设置,则包含module,并与字符串.inc拼接 inc格式一般是图标或者头像格式,因此我们可以初步判断,这个包含应该是基 ...

  7. HDU 4699 Editor(模拟 对顶栈)

    题目大意: 给定一个整数序列 维护5种操作 次数<1e6 I x: 光标位置插入x 然后光标位于x之后 D: 删除光标前一个数 L: 光标左移 R: 光标右移 Q k: 询问位置k之前的最大前缀 ...

  8. ES2.3.5版本的数据类型

    1,最近使用了2.3.5版本的ES,发现在创建索引的时候出了以下错误. (1)例: POST 192.168.11.166:9200/article3/article/_mapping { " ...

  9. sftp和FTP

    sftp 是一个交互式安全文件传输协议的传输程式.它类似于 ftp也叫internet网络文件协议, 但它进行加密传输,比FTP有更高的安全性.下边就简单介绍一下如何远程连接主机,进行文件的上传和下 ...

  10. Python 中的类与对象 初认识

    一:类的声明 1类的关键字: 从第一天第一个项目起我们就接触过关键字,比如False True is not None return for while elif else import等等,这是语言 ...