此示例(void function f(string& s1, string& s2)
)取自B.Stroustup新书“TCPL”第4版第297/298页。
#include <iostream>
#include <functional>
#include <string>
#include <algorithm>
void f(std::string& s1, std::string& s2)
{
std::function<void(char* b, char* e)> rev =
[&](char* b, char* e) { if (1<e-b) { std::swap(*b,*--e); rev(++b,e); } };
rev(&s1[0],&s1[0]+s1.size());
rev(&s2[0],&s2[0]+s2.size());
}
int main()
{
std::string s1("Hello");
std::string s2("World");
f(s1, s2);
std::cout << s1 << " " << s2 << '\n';
}
代码编译并打印出正确的结果,即函数f
反转输入字符串的字符。节目输出:
2009东海生日贺 dlroW
我可以理解下面表达式的语义。我的问题是接受它的语法,因为变量rev
是根据它自己定义的。
std::function<void(char* b, char* e)> rev =
[&](char* b, char* e) { if (1<e-b) { std::swap(*b,*--e); rev(++b,e); }
答案 0 :(得分:7)
lambda通过[&]
引用捕获所有内容。这还包括rev
并允许使用此语法。
答案 1 :(得分:5)
(来自问题下的评论)
请注意细微之处:rev
的声明点在语法上完全与声明符 rev
一致:
// vvv Point of declaration
std::function<void(char* b, char* e)> rev =
[&](char* b, char* e) { if (1<e-b) { std::swap(*b,*--e); rev(++b,e); }
之后(包括等号和后面的所有内容),rev
现在表示具有已知类型(和大小)的有效对象,并且可以像范围中的任何其他已定义变量一样使用它。
另外,请考虑编译器如何构建此代码:
当它编译对rev
的调用时(在函数定义中),这是:
...被调用的实际函数是无关紧要的,只要其签名和位置是已知的(后者的信息在声明时可供编译器使用)。
当然,函数的其余部分也可以直接用于编译器构建。
所以,尽管“根据自身定义一个函数”似乎很奇怪,但它的工作原理很直接。