-
[31] - (C++) For each, Move Semantics, Lambdas, Uniform Initialization - 3Graphics 2021. 8. 5. 15:12
Lambdas
오래 전에 웹 파이썬 프로그래밍 수업을 들을 때 처음 접했던 개념입니다. 학기가 끝나갈 무렵, 앞으로 이런 것들을 공부할 것이라며 알려주었던 기억이 납니다. 전날 눈이 쏟아져 온세상이 차분하게 가라앉은 어느 겨울이었습니다. 돌이켜보면 그 순간과 지금 이 순간 저는 별로 변한 것이 없습니다. 참 괴로운 일이 아닐 수 없습니다.
MSDN의 기본적인 설명은 Lambda는 함수의 argument나 촉발된 곳에서 Anonymous function object의 정의를 간편하게 해주기 위해 C++11 표준부터 지원된 기능이라고 합니다. Anonymous Function(closure)역시 lambda의 다른 이름입니다. 더 엄밀하게 표현을 하면 closure는 lambda expression을 Encapsulate하는 Anonymous Function Object입니다. 이 람다 표현식은 알고리즘이나 async function의 Argument로 전달되는 짧은 코드에 자주 적용되고 있습니다.
Lambda는 Function Object, Function Pointer의 장점만을 차용한 개념인데 Function Object가 syntactic overhead가 적다는 점, Function Pointer가 Scope 내에서 State를 유지할 수 있다는 점을 차용한 것입니다. 그러면서도 단점들은 모두 개선해서 Function Pointer처럼 명시적인 Class의 선언 조차 필요하지 않습니다.
.. Lambda Expression의 한 예시입니다. 정확히는 for_each의 세 번째 Parameter가 lambda expression입니다. [&evecCount]가 람다 표현식이 시작함을 알리며 (int n)이 람다 표현식에 사용될 Parameter를 알립니다. 그리고 남은 중괄호가 Lambda Expression의 Body입니다. 그런에 []부분은 외부에서 parameter를 받는 역할도 함께 수행하는 것 같습니다.
위와 같은 예제는 Function Object를 바탕으로 똑같은 결과를 구현할 수 있습니다.
만약 lambda expression의 식이 시간에 따라서 더 확장되고 빈번한 수정이 일어나게 될 예정이라면 애초부터 lambda를 사용하지 않는 편이 생산성 향상에 큰 도움을 줄 것입니다. 다른 예제도 설명이 잘 되어 있습니다.
기본적인 구조는 [] () "mutable" "throw" -> 'return type' {}; 입니다. Mutable, throw는 option이고 Capture clause, Parameter lists, Lambda Expression은 기본적인 골격입니다. -> return type은 trailing return type으로 명시가 됩니다. 그래서 위의 lambda 표현을 다음과 같이 더 자세히 쓸 수도 있습니다.
컴파일에도 문제가 없습니다 람다 표현식에도 몇 가지 종류가 존재합니다. 먼저 이 예제들처럼 람다 표현식이 필요한 곳게 바로 꽂아주는 방식을 Function Literal이라고 합니다. 그런데 이렇게 매번 필요할 때마다 작성하는 것은 불편하기도 하고 가독성이 심하게 떨어지기도 합니다. 그래서 마치 변수를 초기화하는 것처럼 람다 식도 비슷한 방식으로 초기화 하여 필요할 때마다 꺼내 쓸 수 있습니다.
또 한 가지 재미있는 사실이 있습니다. lambda는 Function이 아니라 일종의 functor라는 사실입니다.
Learn C++의 설명 Capture Clause : []
위에서 했던 것처럼 람다 식은 Capture Clause로 시작됩니다. 어떤 변수를 Address로 참조하려면 Address of (&)를 사용하고 아니면 안 쓰면 됩니다. C++ 14표준부터는 람다의 Body에 새로운 지역변수를 선언할 수 있게 되었습니다. MSDN을 참조하면 다양한 방식으로 Capture clause를 구성할 수 있으며 몇 가지 제한 사항이 있다는 사실을 알 수 있습니다.
몇 가지 Caputer clause 또한, *this 도 사용할 수 있습니다. 연산자만 덩그러니 선언된 것을 Capture-Default &, = 라고 합니다. 만약 이렇게 디폴트 값을 정해주면 같은 연산자는 해당 Capture Clause에 나타날 수 없습니다. Class member fucntion의 body에 lambda expression을 사용하고 싶을 때는 capture clause에 사용하면 됩니다.
또, Ellipsis Expression에서도 사용될 수 있습니다.
Uniform Initialisation
C++11부터 지원이 가능한 기능입니다. primitive부터 Aggregate initialising에 이르기까지 오브젝트나 인스턴스를 일관된 구문으로 초기화 할 수 있도록 합니다.
뿐만 아니라 Class의 Instance까지 초기화 할 수 있습니다.
다음과 같이 함수의 반환값을 이용하여 초기화 할 수도 있습니다.
거의 비슷한 개념이지만 함수의 Parameter를 이용하여 초기화 하는 방법도 존재합니다.
Ref
1. https://docs.microsoft.com/en-us/cpp/cpp/lambda-expressions-in-cpp?view=msvc-160 .
2. https://www.learncpp.com/cpp-tutorial/introduction-to-lambdas-anonymous-functions/.
3. https://www.cplusplus.com/reference/future/async/.
4. https://docs.microsoft.com/en-us/cpp/cpp/lambda-expression-syntax?view=msvc-160.
5. https://docs.microsoft.com/en-us/cpp/standard-library/algorithms?view=msvc-160.
6. https://www.geeksforgeeks.org/functors-in-cpp/.
7. https://www.learncpp.com/cpp-tutorial/function-pointers/(About Function pointers)
8. https://docs.microsoft.com/en-us/cpp/cpp/ellipses-and-variadic-templates?view=msvc-160(Ellipsis Expression)
9. https://docs.microsoft.com/en-us/cpp/cpp/examples-of-lambda-expressions?view=msvc-160(Using Lambda Expression within a class)
10 https://en.cppreference.com/w/cpp/language/parameter_pack(*Important* Packed Parameters)
11. https://www.ibm.com/docs/en/i/7.4?topic=c11-parameter-packs(*Imporant* Packed Parameter and variadic templates)
12. https://docs.microsoft.com/en-us/cpp/cpp/initializing-classes-and-structs-without-constructors-cpp?view=msvc-160(Brace Initialisation)
'Graphics' 카테고리의 다른 글
[33] - Remove_if (0) 2021.08.09 [32] - Copy and Filter (0) 2021.08.09 [30] - (C++) For each, Move Semantics, Lambdas, Uniform Initialization - 2 (0) 2021.08.03 [29] - (C++) For each, Move Semantics, Lambdas, Uniform Initialization - 1 (0) 2021.08.03 [28] - Bindable/Drawable System - 2 (0) 2021.08.02