C++11 부터, 람다 표현식은 함수가 호출 되거나, 함수에 arguments를 전달할 때 anonymous function objects (closures)를 정의 하기 편리한 방법입니다.
람다는 비동기 함수 또는 알고리즘에 전달되는 몇 줄 코드를 캡슐화합니다.
사용 예시
// Lambda 사용
int my_mod = 8;
transform(in.begin(), in.end(), out.begin(),
[my_mod](int v) -> int { return v % my_mod; });
개시자 (introducer), 인자(parameters), 반환 타입(return type), 그리고 함수의 몸통(statement)
- 개시자 [ ] 괄호 안에 외부 변수를 넣는다면, 람다 함수가 이를 캡쳐 해서, 이 변수를 람다 내부에서 사용할 수 있게 됩니다.
위 예시 코드를 보면, my_mod 를 개시자 안에 넣었고, 람다에서 사용하는 것을 확인할 수 있었습니다.
- Parameter ( ) 람다가 실행 시 받을 인자들을 넣습니다. 위 람다는 int 타입의 v_를 인자로 받고 있습니다.
- -> 반환 타입을 지정
-마지막으로 람다 내부에서 실행할 코드를 작성
위와 같이 작성하면, 런타임시 이름은 없지만, 메모리 상에 임시적으로 존재하는 클로져 객체가 생성됩니다.
이 클로져 객체는 함수 객체 처럼 행동합니다.
Capture
나는 해당 부분이 진짜 흥미로웠다.
잘 모르는 것 일 수도 있지만, 리눅스/윈도우 쓰레드는 항상 static 하게 선언해서 사용하게 만들었다. static 쓰게 되다보니, 특정 시점 객체의 멤버 변수를 접근할 수 없는 번거로움이 항상 있었다.
근데, 이 Capture를 잘 이해하고, 활용하면 무적 쓰레드를 사용할 수 있다. 뭐, Parameter에 담아서 보내면 되잖아?
맞긴 한데, STL에서는 내 입맛대로 파라미터를 지정하지 못하는 경우가 많다.
Example)
1. [&]() {/**/} 외부의 모든 변수들을 레퍼런스로 가져온다.( 함수의 call-by-reference를 생각)
2. [=]() {/**/} 외부의 모든 변수들을 값으로 가져온다.( 함수의 Call - by - Value 를 생각)
3. [=, &x, &y] {/**/}, 혹은 [&, x, y]{/**/} 외부의 모든 변수들을 값 또는 레퍼런스로 가져오되, x와 v 만 레퍼런스/ 값으로 가져온다.
4. [x, &y, &z] { /**/ } 지정한 변수들을 지정한 바에 따라 가져온다.
#include <iostream>
#include <functional>
#include <thread>
#include <unordered_map>
#include <algorithm>
class lambdaClass
{
public:
lambdaClass()
:
_count(0)
{
}
virtual ~lambdaClass()
{
}
public:
void Init()
{
_map.insert(std::make_pair(1, "First"));
_map.insert(std::make_pair(2, "Second"));
_map.insert(std::make_pair(3, "Third"));
_map.insert(std::make_pair(4, "Fourth"));
_map.insert(std::make_pair(5, "Fifth"));
}
void Do()
{
for_each(_map.begin(), _map.end(), [&](const std::pair<int, std::string> _pair) { std::cout << "Key: " << _pair.first << " Value: " << _pair.second.c_str() << std::endl; _count++; });
}
uint32_t get_count()
{
return _count;
}
private:
std::unordered_map<int, std::string> _map;
uint32_t _count;
};
int main(void)
{
lambdaClass _lambda;
_lambda.Init();
_lambda.Do();
std::cout << "_count: " << _lambda.get_count() << std::endl;
return 0;
}
왜 캡쳐인지 잘 생각해야합니다. 우리가 컴퓨터 화면을 촬영하는 것을 캡쳐라고 합니다.
int v = 42;
auto func = [=] { cout << v << endl; };
v = 8;
func(); // 실행결과는 42일까, 8일까
위 코드의 실행결과는 42
캡쳐의 범위
캡쳐 되는 개체들은 모두 람다가 정의된 위치에서 접근 가능해야만 합니다.
람다의 전달 및 저장
std::function<int(std::string const &)> f;
f = [](std::string const &s) -> int { return s.size(); };
int size = f("http://itguru.tistory.com");
cout << size << endl;
/////////////////////////////////////////////////////////
std::function<int(int)> f1;
std::function<int(int)> f2 = [&](int i) -> int {
cout << i << " ";
if (i > 5) {
return f1(i - 2);
}
};
f1 = [&](int i) -> int {
cout << i << " ";
return f2(++i);
};
f1(10);
'개발 > C++' 카테고리의 다른 글
std::move, std::forward (0) | 2023.07.25 |
---|---|
EBO (Empty Base Optimization) (0) | 2022.07.17 |
Copy Elision, RVO (0) | 2022.07.07 |
std::function 이란? (0) | 2022.04.11 |
JsonCpp 사용법 (2) | 2022.02.04 |