繁体   English   中英

C ++ 14中的Lambda-Over-Lambda

[英]Lambda-Over-Lambda in C++14

接下来的递归lambda调用如何结束/终止?

#include <cstdio>

auto terminal = [](auto term)            // <---------+  
{                                        //           |
    return [=] (auto func)               //           |  ???
    {                                    //           |
        return terminal(func(term));     // >---------+
    };
};


auto main() -> int
{
    auto hello =[](auto s){ fprintf(s,"Hello\n"); return s; };
    auto world =[](auto s){ fprintf(s,"World\n"); return s; };


    terminal(stdout)
            (hello)
            (world) ;

    return 0;

}

我在这里想念什么?

Running code

这不是递归函数调用,请分步看一下:

  1. terminal(stdout) -这只是返回捕获了stdout的lambda
  2. 用lambda hello调用1.的结果,它执行lambda( func(term) ),其结果被传递给terminal() ,后者仅像1一样返回lambda。
  3. 2.的结果被lambda world调用,它的功能与2相同,但是这次返回值被丢弃了。

调用本身不是递归的。 它返回一个功能对象,如果调用该功能对象,它将再次调用terminal以生成另一个功能对象。

因此, terminal(stdout)返回一个函子,该函子捕获stdout并可以与另一个函数对象一起调用。 再次调用(hello) ,使用捕获的术语stdout调用hello函子,输出"Hello" ; 调用terminal并返回另一个函数,这次捕获了hello的返回值-仍然是stdout 再次调用该函子(world) ,输出"World"

这里的关键是要了解这是有效的:

world(hello(stdout));

并打印“ Hello World”。 递归的lambda系列可以展开为

#include <cstdio>

auto terminal = [](auto term)            // <---------+  
{                                        //           |
    return [=] (auto func)               //           |  ???
    {                                    //           |
        return terminal(func(term));     // >---------+
    };
};

/*
terminal(stdout) -returns> anonymous_lambda which captures stdout (functor)
anonymous_lambda(hello) is called, func(term) is hello(stdout) and prints "Hello" and returns stdout, the anonymous_lambda -returns> terminal(stdout)
(the above 2 lines start again)
terminal(stdout) is called and -returns> anonymous_lambda which captures stdout (functor)
anonymous_lambda(world) is called, func(term) is world(stdout) and prints "World" and returns stdout, the anonymous_lambda -returns> terminal(stdout)
terminal(stdout) is called and -returns> anonymous_lambda which captures stdout (functor)
nobody uses that anonymous_lambda.. end.
*/

auto main() -> int
{
    auto hello =[](auto s){ fprintf(s,"Hello\n"); return s; };
    auto world =[](auto s){ fprintf(s,"World\n"); return s; };

    world(hello(stdout));


    terminal(stdout)
            (hello)
            (world) ;

    return 0;

}

Coliru示例

可以在内部将其转换为如下所示的内容:

#include <cstdio>

template <typename T>
struct unnamed_lambda
{
    unnamed_lambda(T term) : captured_term(term) {}

    template <typename A>
    unnamed_lambda operator()(A func);

    T captured_term;
};

struct terminal_lambda
{
    template <typename A>
    unnamed_lambda<A> operator()(A term)
    {
        return unnamed_lambda<A>{term};
    }
};

terminal_lambda terminal;

template <typename T>
template <typename A>
unnamed_lambda<T> unnamed_lambda<T>::operator()(A func)
{
    return terminal(func(captured_term));
}

struct Hello
{
    FILE* operator()(FILE* s)
    {
        fprintf(s, "Hello\n");
        return s;
    }
};

struct World
{
    FILE* operator()(FILE* s)
    {
        fprintf(s, "World\n");
        return s;
    }
};

int main()
{    
    Hello hello;
    World world;
    unnamed_lambda<FILE*> l1 = terminal(stdout);
    unnamed_lambda<FILE*> l2 = l1(hello);
    unnamed_lambda<FILE*> l3 = l2(world);

    // same as:
    terminal(stdout)(hello)(world);
}

现场演示

实际上,这就是编译器使用lambda(有一些近似值) 在后台执行的操作

我认为混淆的根源来自将lambda声明读取为lambda调用。 确实在这里:

auto terminal = [](auto term)            // <---------+  
{                                        //           |
    return [=] (auto func)               //           |  ???
    {                                    //           |
        return terminal(func(term));     // >---------+
    };
};

作者刚刚声明了一个lambda terminal ,该terminal接受一个任意参数term并返回未命名的lambda,仅此而已! 让我们看一下这个未命名的lambda:

  • 接受可调用对象func作为参数,并在复制捕获的参数term上调用它,并且
  • 返回带有调用func(term)的结果的terminal的结果; 因此它返回另一个未捕获的lambda来捕获func(term)的结果,但是现在尚未调用此lambda,因此没有递归。

现在主要的技巧应该更加清楚:

  1. terminal(stdout)返回捕获了stdout的未命名lambda。
  2. (hello)将此未命名的lambda称为arg传递给可调用的hello。 这将在先前捕获的标准输出上调用。 hello(stdout)再次返回stdout,用作对终端的调用的参数,并返回另一个捕获了stdout的未命名lambda。
  3. (world)与2相同。
  1. terminal(stdout)返回一个带有参数func函数x 所以:

    terminal(stdout) ==> x(func) { return terminal(func(stdout)) };

  2. 现在terminal(stdout)(hello)调用函数x(hello)

    terminal(stdout)(hello) ==> x(hello) { return terminal(hello(stdout)) };

    这导致hello函数被调用并再次返回函数x

  3. 现在terminal(std)(hello)(world)调用函数x(world)

    terminal(stdout)(hello) ==> x(world) { return terminal(world(stdout)) };

    这导致world函数被调用并再次返回函数x 由于不再有参数,现在不再调用函数x

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM