在下面的示例中,函数对象"rev"是根据其自身定义的.这怎么可能?

Wak*_*zil 4 c++ lambda functor c++11

这个例子(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';
}
Run Code Online (Sandbox Code Playgroud)

代码编译并打印出正确的结果,即函数f反转输入字符串的字符.节目输出:

olleH 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); } 
Run Code Online (Sandbox Code Playgroud)

typ*_*232 7

lambda通过引用捕获所有内容[&].这还包括rev并允许此语法.


Dan*_*aum 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); }
Run Code Online (Sandbox Code Playgroud)

之后(包括等号和后面的所有内容),rev现在表示具有已知类型(和大小)的有效对象,并且可以像范围中的任何其他已定义变量一样使用它.

另外,请考虑编译器如何构建此代码:

当它编译调用rev(在函数定义内)时,这是:

  • 简单地构建一个堆栈框架(已传递已知参数),和
  • 调用jmp(到一个已知的地址)

...被调用的实际函数是无关紧要的,只要其签名和位置是已知的(后者的信息在声明时可供编译器使用).

当然,函数的其余部分也可以直接用于编译器构建.

因此,尽管"根据自身定义一个函数"看似奇怪,但它的工作原理很直接.