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

时间:2014-02-05 18:22:18

标签: c++ c++11 lambda functor

此示例(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); } 

2 个答案:

答案 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的调用时(在函数定义中),这是:

  • 只需构建堆栈框架(已传递已知参数)和
  • 调用jmp (到已知地址)

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

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

所以,尽管“根据自身定义一个函数”似乎很奇怪,但它的工作原理很直接。