Joh*_*uld 8 c++ lambda closures c++11
我遇到了一个挑战我对C++ lambdas的新生理解的情况,我把它简化为以下内容:
#include <iostream>
void test()
{
int (*func)();
func =
[]()->int {
std::cerr << "func()" << std::endl;
return 0;
};
int i = 0;
func =
[i]()->int {
std::cerr << "func(): i= " << i << std::endl;
return 0;
};
}
Run Code Online (Sandbox Code Playgroud)
在第一种情况下,我将一个非常简单的lambda分配给一个函数指针,它看起来像我期望的那样工作.我在第二种情况下尝试做的是为lambda提供对值的访问i.我对[i]()->int {代码的理解}是它定义了一个没有参数的无名函数,返回一个int并且,通过C++ 11独角兽的魔力,知道它的当前值i.我希望这个lambda应该可以调用int(*)().
test.cpp: In function ‘void test()’:
test.cpp:14:7: error: cannot convert ‘test()::__lambda1’ to ‘int (*)()’ in assignment
func =
^
Run Code Online (Sandbox Code Playgroud)
似乎gcc 4.8.1和4.8.2不同意我的评估(4.4.1甚至拒绝讨论此事).
这似乎表明第二个lambda的类型与函数指针不是赋值兼容的.我不明白为什么会出现这种情况,因为该表达式应该可以调用为" int(*)()".
我的理解(或独角兽)在哪里失败了?
C++标准,第5.1.2/6节,定义了lambda如何转换为(可能是模板)函数指针.
特别是:
对于一个非通用λ-表达的闭合类型没有λ-捕获具有公共非虚拟非显式const的转换功能,以函数指针与C++语言联动装置(7.5),其具有相同的参数和返回类型为闭包类型的函数调用操作符.此转换函数返回的值应为函数的地址,该函数在调用时与调用闭包类型的函数调用运算符具有相同的效果
由于lambda具有捕获功能,因此无法转换为函数指针.
注意:
即以下内容无效:
int i = 0;
func =
[&]()->int {
std::cout << "func(): i= " << i << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
可通过签名调用int()并不意味着它可以转换为int(*)(). 任何具有重载的东西都int operator()()可以通过这种方式调用。
Lambda 函数通过这样的重载创建了漂亮的标准类,然后将它们包装在一些语法糖中。(不真实,但足够真实)1
无状态 lambda(不捕获任何内容)会带来额外的operator int(*)()超载(或operator Signature*一般情况),但这只是额外的好处,而不是 lambda 的核心。
实际上,函数指针是调用函数时执行跳转到的地址。也没有空间容纳数据指针(用于存储捕获的变量的状态)。理论上,您可以在执行代码旁边或内部为数据分配空间,但许多系统出于安全原因也会阻止将可写页面标记为可执行,这使得该系统不切实际。有人提出过这样的延期。
1与 C++ 标准中的许多内容一样,内容是根据行为而不是实现来指定的。lambda 的大多数功能都可以通过为您实现“自动编写”的 bog 标准类来复制,但即便如此,编译器也不必这样做。某些 lambda 实现(例如基于堆栈帧捕获的[&]lambda)无法在 C++ 语言中实现。