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

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