C ++ 14의 Lambda-Over-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;
}
여기서 내가 뭘 놓치고 있니?
재귀 함수 호출이 아닙니다. 단계별로 살펴보십시오.
terminal(stdout)
-이것은 단순히 캡처 한 람다를 반환합니다.stdout
- 1의 결과는 lambda와 함께 호출되어
hello
람다 (func(term)
) 를 실행하고 그 결과는로 전달terminal()
되며 1과 같이 단순히 람다를 반환합니다. - 2의 결과는 람다로 호출
world
되는데, 이는 2와 동일하게 수행되며 이번에는 반환 값이 삭제됩니다.
호출 자체는 재귀 적이 지 않습니다. 호출되면 terminal
또 다른 함수 객체를 생성하기 위해 다시 호출 할 함수 객체를 반환 합니다.
따라서 다른 함수 객체 terminal(stdout)
를 캡처 stdout
하고 호출 할 수 있는 펑터를 반환 합니다. 다시 (hello)
호출 hello
하면 캡처 된 용어를 사용 하여 펑터를 호출하여 stdout
출력합니다 "Hello"
. 호출 terminal
및 반환이 시간의 반환 값 캡처 다른 펑 hello
- 아직도있다 stdout
. 그 펑터를, (world)
다시 똑같이 호출 하여 "World"
.
여기서 핵심은 이것이 유효하다는 것을 이해하는 것입니다.
world(hello(stdout));
"Hello World"를 인쇄합니다. 재귀 적 일련의 람다는 다음과 같이 풀 수 있습니다.
#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;
}
내부적으로 다음과 같은 것으로 번역 될 수 있습니다.
#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);
}
실제로 이것은 컴파일러가 람다 (일부 근사값 포함)로 장면 뒤에서 수행하는 작업 입니다.
I think that the source of confusion comes from reading a lambda declaration as a lambda call. Indeed here:
auto terminal = [](auto term) // <---------+
{ // |
return [=] (auto func) // | ???
{ // |
return terminal(func(term)); // >---------+
};
};
the author just declared a lambda terminal
which takes one arbitrary argument term
and returns an unnamed lambda, nothing more! Let's look at this unnamed lambda, it:
- accepts a callable object
func
as argument and calls it on the copy-captured parameterterm
and - returns the result of terminal called with the result of the call
func(term)
; so it returns another unnamed lambda that captures the result offunc(term)
, it but this lambda is not called by now, there is no recursion.
Now the trick in the main should be more clear:
terminal(stdout)
returns an unnamed lambda which has captured stdout.(hello)
calls this unnamed lambda passing as arg the hello callable. This gets called on the stdout previously captured.hello(stdout)
returns again stdout which is used as argument of a call to terminal, returning another unnamed lambda which has captured stdout.(world)
same as 2.
terminal(stdout) returns a function, let's call it function
x
, with paramfunc
. So:terminal(stdout) ==> x(func) { return terminal(func(stdout)) };
Now terminal(stdout)(hello) calls function
x(hello)
:terminal(stdout)(hello) ==> x(hello) { return terminal(hello(stdout)) };
This results in
hello
function get called and returns functionx
again.Now terminal(std)(hello)(world) calls function
x(world)
:terminal(stdout)(hello) ==> x(world) { return terminal(world(stdout)) };
This results in
world
function get called and returns functionx
again. Functionx
now is not called any more as there is no more param.
참고URL : https://stackoverflow.com/questions/25618934/lambda-over-lambda-in-c14
'code' 카테고리의 다른 글
Go에서 중첩 된 함수 선언 (함수 내부 함수)을 허용하지 않는 이유는 무엇입니까? (0) | 2020.11.05 |
---|---|
objdump를 사용하여 하나의 단일 함수를 분해하는 방법은 무엇입니까? (0) | 2020.11.05 |
목록에서 두 번째 요소를 어떻게 얻을 수 있습니까? (0) | 2020.11.05 |
다양한 RAISERROR 심각도 수준은 무엇을 의미합니까? (0) | 2020.11.05 |
멀티 태스킹, 멀티 스레딩 및 멀티 프로세싱의 차이점은 무엇입니까? (0) | 2020.11.04 |