4. - 객체를 마치 함수처럼 사용하기에 붙여진 이름.(== Functor)
- 함수가 되기 위한 조건 중 하나는 괄호
(함수 호출 연산자,Function call operator)를 사용해 파라미터 목록을
받는 것.
- 어떤 객체를 함수처럼 사용한다는 것은 객체에 괄호를 붙여서 마치 겉
보기엔 함수를 호출하는 것처럼 사용한다는 의미.
- 컴파일러가 이해할 수 있도록 클래스 안에서 함수호출 연산자를
오버로딩 해줘야 한다.
함수 객체(Function Object)01
4
6. - 함수객체를 사용하는 이유는 성능상에서 이점을 가져올 수 있습니다.
- STL을 이용할 때 인자로 함수를 받는 케이스들이 있습니다.
ex) std::for_each(), std::count_if()
- 이 때 인자로 함수 객체를 넘겨주게 되면, 그 바디가 인라인되어
성능에 상당한 이점을 가져갈 수 있습니다.
함수 객체(Function Object)01
6
8. - C++ 11에 추가된 개념
- 함수 객체 (Function Object)보다 쉽고 편하게 사용할 수 있는 표
기법.
- 익명 함수 객체를 정의하고 사용하는 표기법.
- Java, C# 등 타 언어에서도 많이 쓰이는 개념.
C++ Lambda02
8
9. - Lambda는 크게 4개의 부분으로 구성되어 있습니다.
1. 개시자(Introducer)
2. 인자(Parameters)
3. 반환 타입(Return Type)
4. 함수의 몸통(Statement)
C++ Lambda02
9
10. - 개시자(Introducer)
- 괄호 안에 어떤 외부 변수(my_mod)를 입력하게 되면 람다 함수
가 이를 캡쳐해서, 해당 변수를 람다 내부에서 이용할 수 있게 됩니
다.
C++ Lambda02
10
11. - 인자(Parameters)
람다가 실행 시 받을 인자를 입력.
- 반환 타입 (Return Type)
람다가 종료될 때 반환할 타입 선언
- 몸통 (statement)
람다에서 실행할 내용.
C++ Lambda02
11
12. - Closure == Closed over(Closure)
- 코드 상에 람다가 존재할 경우, 런타임 시 이름은 없지만,
메모리 상에 임시적으로 존재하는 Closure 객체가 생성됩니다.
- Closure 객체는 함수 객체 처럼 행동합니다.
- lazy evaluation (늦은 평가)이 가능합니다.
C++ Lambda02
12
14. - 어떤 벡터의 원소들의 모든 곱을 계산하는 코드를 작성해 볼 예정
입니다.
- 각각 iterator / Functor / Lambda를 이용해서 작성해 볼 예정입니
다.
C++ Lambda Practice03
14
15. - 첫번째로 작성 해볼 코드는 바로 Iterator만을 사용한 코드입니다.
C++ Lambda Practice03
15
16. - Functor를 이용해서 작성한
코드 예제 입니다.
- for_each를 사용해 이전 코
드의 while문을 모두 없앨 수
있습니다.
- 하지만 Functor를 구성하는
코드를 작성하기 위해 위에
struct를 생성, void operator()
정의하는 부분이 추가되었습
니다.
C++ Lambda Practice03
16
17. - Lambda를 이용해서 작성한 코드 예제 입니다.
- 짧고 간결하며, 깔끔하게 for_each문을 사용할 수 있게 되었
습니다.
C++ Lambda Practice03
17
18. - 람다식의 맨 뒤에 괄호()를 붙여서 바로 임시 클로져 객체를
실행시킬 수도 있습니다.
- 리턴 타입이 void일 경우 ‘->’ 를 생략할 수 있습니다.
- 받는 인자가 없을 경우, ()를 생략할 수 있습니다.
C++ Lambda Practice03
18
20. - 람다 안에서 람다 밖에 있는 변수들에게 접근하고자 할 때, 인자로 해당
변수들을 받을 수 없는 상황에서 접근할 수 있는 방법을 제공합니다.
- 라이브러리를 사용하게 될 때 함수의 인자를 맞춰줘야 하는 상황이 생
기는데, 이 때 람다 내부와 외부가 ‘소통할 수 있게 하는 문’ 이라고 생각하
시면 될 것 같습니다.
Ex) C++ STL
- 캡쳐 하고자 하는 내용은 ‘[]’ 안에 적용하게 되는데, 대표적으로 4가지
의 형태를 지니고 있습니다.
Capture04
21
21. 1. [&]() { /* */ }
- 외부의 모든 변수들을 레퍼런스로 가져온다.(함수의 Call-by-Reference)
2. [=]() { /* */ }
- 외부의 모든 변수들을 값으로 가져온다.(함수의 Call-by-value)
3. [=, &x, &y] { /* */ } , 혹은 [&, x, y] { /* */ } 외부의 모든 변수들을 값/레퍼런스로 가져
오되, x와 y만 레퍼런스/값으로 가져온다.
Capture04
22
22. Capture04
23
- 여기서 예제 코드와 같은 형식으로 작성했을 때, 캡쳐를 레퍼런스가 아닌 값으
로 했을 때 변수를 언제 캡쳐하게 될까요?
- 람다는 클로져 객체가 처음 생성될 때 변수들의 값을 캡쳐하게 됩니다.
- 캡쳐를 값으로 할 때 주의점은 그 변수들에는 자동으로 const 속성이 붙는다는
것입니다.
23. Capture04
24
위 예제에서는 cardinal에 있는 원소들을 for_each를 통해 순회하면서
total_elements에 곱하게 됩니다. 이 때 캡쳐는 & 이므로 외부 변수인
total_elements를 캡쳐 해서 수정할 수 있었습니다.
25. Capture04
27
- Call-by-Value 형식의 캡쳐를 사용하게 되면 이와 같은 컴파일 에러를 발생하
게 됩니다.
- 위 코드에서 total_elements는 값으로 전달 받았으므로 const인데, 값을 바꾸
려고 하니 에러가 발생한 것입니다.
- 그렇다면 함수 내부에서 값을 바꾸고자 하면 어떻게 해야할까요?
26. Capture04
28
- 답은 mutable 속성을 추가해주시면 됩니다.
- 람다 함수 외부의 지역변수인 i의 값은 변하지 않고, 오직 람다 함수 내부의 ‘ 어
떤 다른 i ’의 값이 변하는 것을 확인할 수 있습니다.
28. 클로져 객체의 복사 생성자와 소멸자05
30
- 모든 클로져 객체들은 암묵적으로 복
사 생성자와 소멸자를 가지고 있습니다.
- 먼저 복사 하지 않는 상황에서 람다
를 사용하는 예제를 먼저 보겠습니다.
- f에서 t를 사용하지 않았으므로, t를
캡쳐하지 않게 됩니다.
29. 클로져 객체의 복사 생성자와 소멸자05
31
- 먼저 m1를 생성하면서, 람다가 t를 캡쳐
했으므로 t의 복사 생성자가 호출되게 됩니
다. 왜냐면 캡쳐를 값으로 받았기 때문이죠.
- 아래의 auto m2 = m1; 에서 클로져 객
체의 복사 생성이 일어나는데, 이 때 클로
져 객체의 복사 생성자가 값으로 캡쳐된 객
체들을 똑같이 복사 생성해주게 됩니다.
30. 클로져 객체의 복사 생성자와 소멸자05
32
- 위에 말씀드렸던 것처럼, 캡쳐를 레
퍼런스로 받게 되면 복사 생성자가 호
출되지 않게 됩니다.
32. 람다의 전달 및 저장06
34
- 람다의 전달 방식의 또다른 방법으로
는 함수 포인터를 이용하는 방법이 있
습니다.
- 이 경우에는 람다가 캡쳐하는 것이
없어야 합니다.
33. 람다의 전달 및 저장06
35
- 람다 캡쳐하는 부분에 캡쳐
하는 방식을 전달하게 될 경우
적절한 변환 함수가 없다며 컴
파일 에러를 내게 됩니다.
34. 람다의 전달 및 저장06
36
- C++ 11에서는 클로져 객체를 전달하고 또 저장할 수 있는 기능이 제공됩니다.
- 바로 std::function입니다. 스 어떤 클로져 객체나 함수 등을 모두 보관 할 수 있는 저장소 입니다.
- 참고로 Visual Studio 2010에서는 <functional> 을 include 시켜줘야합니다.
35. 람다의 전달 및 저장06
37
- auto 키워드를 이용할 경우 변수를 정의할
때 해당 변수가 명확하게 구현되어야 컴파일
에서 타입을 추정할 수 있습니다.
- auto를 이용하게 되면, 처음 캡쳐 부분에서
캡쳐하는 대상의 타입이 명확히 정해지지 않
은 상태이므로 타입을 추정할 수 없게 됩니다.
36. 람다의 전달 및 저장06
38
- std::function을 이용할 경우 f1을 먼저 선언
만 해놓은 뒤 f2를 구현하고, 다시 f1을 구현할
수 있게 됩니다.
37. 람다의 전달 및 저장06
39
- std::function을 사용하면 람다 함수로 재귀 호출 함수도 구현할 수 있게 됩니다.
38. 참고 자료07
40
- 초보자를 위한 C++ 200제 (2판)
- 씹어먹는 C++ 토막글 (https://modoocode.com/196)
- VallistA C++11 :: Lamda Expression
https://vallista.tistory.com/entry/C-11-Lambda-Expression-
%EB%9E%8C%EB%8B%A4-%ED%91%9C%ED%98%84%EC%8B%9D-
%ED%95%A8%EC%88%98-%EA%B0%9D%EC%B2%B4-Functor
- jacking75 https://jacking75.github.io/cpp_stl_function/