lambda 표현식
람다 vs 클로저?
c++11 부터 지원하는 람다 식은 말그대로 표현식이며 소스코드 상에서만 존재하고 컴파일 이후 익명함수 객체(클로저)를 생성하는 식을 의미한다.
auto f = [&](int x, int y) { return fudgeFactor * (x + y); };
여기서 = 오른쪽에 있는 식이 람다식이며 컴파일 이후에는 클로저로 변한다. f는 클로저가 아닌 클로저의 복사본이며 식의 끝줄에서 파괴된다.
보통 람다식은 함수의 인자로 사용될 함수 객체를 간단하게 정의하기 위해 사용된다.
람다 표현식 구조

1. capture (필수)
람다식 외부에서 선언한 변수들을 내부에서 사용하고 싶을때 변수명을 적으면 된다. 캡쳐하고 나면 클로저의 멤버변수가 된다.
변수마다 reference 방식과 value 방식중 선택할 수 있으며, reference 방식을 선택하면 람다식 내부에서 변경한 값이 외부 변수에서도 적용된다.
변수명을 지정하지 않고 =, &를 지정하면 람다식 본문에서 사용되는 모든 변수가 캡쳐된다.
[] : 아무것도 캡처하지 않음
[&x]: x만 Capture by reference
[x] : x만 Capture by value
[&] : 람다 본문에서 사용되는 모든 외부 변수를 Capture by reference
[=] : 본문에서 사용되는 모든 외부 변수를 Capture by value
[x,y] : x,y 를 Capture by value
[&x,y] : x는 Capture by reference , y는 Capture by value
[&x, &y] : x,y 를 Capture by reference
[&, y] : 본문에서 사용되는 모든 값을 Capture by reference, y는 value
[=, &x] : 본문에서 사용되는 모든 값을 Capture by value, x는 reference
this 변수 캡쳐
클래스의 멤버함수에서 람다를 사용할때 클래스의 멤버변수나 메서드를 호출하기 위해 this 포인터를 캡쳐할 수 있다.
this는 포인터이기 때문에 this에 접근해서 값을 변경하는것도 가능하다.
class Example {
int value;
void foo() {
auto lambda = [this]() {
value = 42; // this->value = 42;
return member_function();
};
}
int member_function() { return value; }
};
c++17 버전부터 *this도 캡쳐가 가능하게 되었다람다 . 이렇게 캡쳐하게 되면 멤버를 읽을순 있지만, 변경은 불가능하다.
2. 매개변수 목록
람다함수로 전달할 매개변수 목록을 받는다.
제네릭 람다 (c++14)
auto add = [](auto x, auto y) { return x+y; };
auto result1 = add(1.3, 2); // double, double, int 형으로 반환
string result2 = add(string("test"), 'p'); // string, string, char 형으로 반환
3. mutable
람다 본문에서 캡쳐한 변수들은 const로 처리되어 값을 변경할 수 없지만, mutable 키워드를 사용하면 람다 본문내에서 변경이 가능하다.
당연히 외부의 실제 변수에는 영향을 주지 않으며, &로 참조 캡쳐한 경우엔 mutable 없이도 변경이 가능하다.
value로 캡쳐된 변수는 람다식이 객체화 될때 클로저객체 내에서 같은 변수(멤버)로 유지되며,
mutable키워드를 지정한 경우 클로저 내에 저장된 변수를 수정할 수 있게된다.
그래서 아래와 같은 상황에서 변수 x의 값이 계속해서 누적된다.
int x = 0;
auto inc = [x]() mutable -> int {
x++;
return x;
};
int incX = 0;
for (int i = 0 ; i < 10; i++)
incX = inc();
cout << incX << endl; // 10
cout << x << endl; // 0
4. 예외사양
람다식에서 어떤 예외들이 발생될 수 있는지 미리 지정할 수 있다.
예외사양에 맞지 않은 예외가 발생될 가능성이 있다면 컴파일시 경고를 표시하며, 실행 중 해당 예외가 발생하면 런타임에러를 발생시킨다.
기본값은 unspecified 이며, 예외가 발생될지, 발생되지 않을지 모른다는 의미를 갖는다.
[]() noexcept { throw 5; }(); // 예외 없음인데, 5 예외를 던졌다.
5. 반환형
람다함수의 리턴타입을 의미하며, 자동으로 추론되기 때문에 꼭 반환형을 명시할 필요는 없다.
6. 람다 식 바디 (필수)
람다식의 동작을 작성한다.
Comments