[C++] lambda (bind 보다는 lambda를 쓰자)
lambda가 왜 필요하냐면,
함수 포인터는 함수이기 때문에 상태를 가질 수 없다.
반복문 같은데 인자로 함수를 넘겨야 하는 상황에서 그 함수가 상태를 가져야 하는 경우, 함수 포인터를 사용할 수 없다.
따라서 상태를 가지는 함수를 만들기 위해서 함수 객체라는 트릭을 사용해야 했다.
함수 객체는 객체인데, ``cpp operator()``를 오버로드해서 함수처럼 호출할 수 있는 객체를 의미한다.
Function object는 보통 Functor라고 부른다.
```cpp
struct Functor {
void operator()() {
std::cout << "Functor" << std::endl;
}
};
```
이렇게 별도의 Functor를 정의해주는 것이 번거롭고 지저분하다.
그래서 상태를 가지는 함수를 표현하기 위해 lambda를 사용한다.
```cpp
[captures](parameters) { body }
// mutable, exception, trailing-return-type 지정도 가능하나 선택 사항이다.
```
캡쳐할 변수를 `` []``에 지정하면 된다. 기본은 값 캡쳐이며 ``c &var``를 지정하면 참조 캡쳐다.
캡쳐할 변수를 명시적으로 지정하지 않아도, 바디에서 쓰이는 변수가 자동으로 캡쳐되도록 할 수 있다.
- ``c [&]`` 바디에서 쓰이는 모든 변수, 상수를 참조로 캡쳐하고 현재 객체 참조 캡쳐.
- ``c [=]`` 바디에서 쓰이는 모든 변수, 상수를 값으로 캡쳐하고 현재 객체 참조 캡쳐.
- ``c []`` 아무것도 캡처하지 않음.
- ``c [this]`` 현재 객체 참조 캡쳐
* 참고. ``cpp std::bind()``에서 참조 캡쳐(?)처럼 사용하려면 ``cpp cref(variable)``를 사용한다. 보통 bind 보다는 그냥 람다 쓰는게 좋다.
다음과 같이 람다 내부에서 외부에 있는 변수의 값을 수정할 수 있다.
```cpp
int i = 0;
auto f = [&i](std::string name) {std::cout << ++i << name << '\n'; };
f("umbum");
std::cout << i << '\n';
```
```
1umbum
1
```
그런데, 람다 내부에서 외부에 있는 변수를 참조가 아니라 값으로 받아와 수정하고 싶다면 ``cpp mutable``을 붙여주어야 한다.
```cpp
int i = 0;
auto f = [i](std::string name) mutable {std::cout << ++i << name << '\n'; };
f("umbum");
std::cout << i << '\n';
```
```
1umbum
0
```
``cpp this``를 넣으면 현재 객체를 참조 캡쳐할 수 있다.
lambda는 friend 함수로, ``cpp private``로 지정된 멤버에도 접근 가능하다.
```cpp
[this]() { std::cout << "cls name : " << name << std::endl; }();
```
bind와 bind1st는 호환이 되긴 된다.
근데 ``cpp bind1st(), binder1st`` 같은 경우 C++11에서 deprecated 되었고,
그냥 ``cpp bind()``는 람다의 한계(템플릿으로 여러 타입 받기, move capture)로 아직까지는 사용하나 이런 케이스가 아니라면 그냥 람다를 사용하는 편이 좋다.
```cpp
void lambda_test() {
int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
const int N = sizeof(x) / sizeof(int);
typedef boost::transform_iterator<std::function<int(int)>, int*> doubling_iterator;
std::function<int(int)> doubling_lambda = [](int x) { return x * 2; }; // or just auto.
doubling_iterator i(x, doubling_lambda);
doubling_iterator i_end(x + N, doubling_lambda);
std::cout << "multiplying the array by 2:" << std::endl;
while (i != i_end)
std::cout << *i++ << " ";
std::cout << std::endl;
}
```
'Languages & Frameworks > C C++' 카테고리의 다른 글
[C++] 생성자에서 throw하면(exception) 객체가 없어질까? / thread는 start() 함수로? (0) | 2018.09.12 |
---|---|
[C++] thread는 context가 필요하다. (0) | 2018.09.11 |
[C++] 컨테이너 안에 클래스가 들어있을 때, 클래스 안의 멤버들을 순회하는 이터레이터를 반환받는 방법 + mem_fn (0) | 2018.09.03 |
[C/C++] strncpy()는 NULL문자를 넣어주지 않는다. (0) | 2018.08.21 |
[C++] \r이 포함된 문자열 출력할 때 이상하게 출력되는 현상 (0) | 2018.08.21 |