int main() { int x = 10; auto func = [](int a, int b) { // std::cout << x; // 컴파일 오류: x를 캡처하지 않음 return a + b; }; std::cout << func(1, 2) << std::endl; // 출력: 3 return 0;}
[var] (값으로 캡처 - by value)
외부 변수 var의 값을 람다 객체 생성 시 복사합니다. 람다 본문 내에서 var의 값을 변경해도 외부의 원본 var에는 영향을 주지 않습니다. 기본적으로 const로 캡처됩니다.
값으로 캡처하는 람다
int main() { int x = 10; auto func = [x](int a) { // x++; // 컴파일 오류: 값으로 캡처된 변수는 기본적으로 const return a + x; }; x = 20; // 람다 내부의 x는 영향을 받지 않음 std::cout << func(5) << std::endl; // 출력: 15 (5 + 10) return 0;}
mutable 키워드: 값으로 캡처된 변수를 람다 내부에서 수정하고 싶다면, 매개변수 목록 뒤에 mutable 키워드를 붙여야 합니다.
mutable 키워드를 사용한 값 캡처
int main() { int x = 10; auto func = [x](int a) mutable { // mutable 키워드 추가 x++; // 이제 람다 내부의 x는 수정 가능 (원본 x와 별개) return a + x; }; std::cout << func(5) << std::endl; // 출력: 16 (5 + 11) std::cout << x << std::endl; // 출력: 10 (원본 x는 변함 없음) return 0;}
[&var] (참조로 캡처 - by reference)
외부 변수 var를 참조로 캡처합니다. 람다 본문 내에서 var를 변경하면 외부의 원본 var도 변경됩니다.
참조로 캡처하는 람다
int main() { int x = 10; auto func = [&x](int a) { // x를 참조로 캡처 x++; // 원본 x를 변경 return a + x; }; std::cout << func(5) << std::endl; // 출력: 16 (5 + 11) std::cout << x << std::endl; // 출력: 11 (원본 x가 변경됨) return 0;}
[=] (모든 변수를 값으로 캡처)
람다 본문 내에서 사용되는 모든 외부 변수를 값으로 캡처합니다. (예외: this 포인터는 항상 참조로 캡처됩니다.)
모든 변수를 값으로 캡처하는 람다
int main() { int x = 10; int y = 20; auto func = [=](int a) { // x, y 모두 값으로 캡처 return a + x + y; }; std::cout << func(5) << std::endl; // 출력: 35 return 0;}
[&] (모든 변수를 참조로 캡처)
람다 본문 내에서 사용되는 모든 외부 변수를 참조로 캡처합니다.
모든 변수를 참조로 캡처하는 람다
int main() { int x = 10; int y = 20; auto func = [&](int a) { // x, y 모두 참조로 캡처 x++; y--; return a + x + y; }; std::cout << func(5) << std::endl; // 출력: 35 (a=5, x=11, y=19) std::cout << "x: " << x << ", y: " << y << std::endl; // 출력: x: 11, y: 19 return 0;}
혼합 캡처: 특정 변수는 값으로, 다른 변수는 참조로 캡처할 수 있습니다.
혼합 캡처 예시
int main() { int x = 10; int y = 20; auto func = [x, &y](int a) { // x는 값으로, y는 참조로 // x++; // 오류: x는 const로 캡처됨 y++; // y는 수정 가능 return a + x + y; }; std::cout << func(5) << std::endl; // 출력: 36 (a=5, x=10, y=21) std::cout << "x: " << x << ", y: " << y << std::endl; // 출력: x: 10, y: 21 return 0;}
[this] (C++11) / *this (C++17): 멤버 함수 내에서 람다를 정의할 때, 람다 내부에서 클래스의 멤버 변수나 멤버 함수에 접근하려면 this 포인터를 캡처해야 합니다.
[this]: this 포인터를 참조로 캡처합니다.
[*this] (C++17): 현재 객체(*this)를 값으로 복사하여 캡처합니다. 복사본이므로 원본 객체와 람다의 생명 주기를 분리할 때 유용합니다.
#include <iostream>#include <vector>#include <algorithm> // sort#include <string>struct Person { std::string name; int age;};int main() { std::vector<Person> people = { {"Alice", 30}, {"Charlie", 25}, {"Bob", 35} }; // 나이 기준 오름차순 정렬 (람다 사용) std::sort(people.begin(), people.end(), [](const Person& p1, const Person& p2) { return p1.age < p2.age; }); std::cout << "Sorted by age:\n"; for (const auto& p : people) { std::cout << p.name << " (" << p.age << ")\n"; } // 출력: // Charlie (25) // Alice (30) // Bob (35) return 0;}
std::find_if와 람다 사용 예시
#include <iostream>#include <vector>#include <algorithm> // find_ifint main() { std::vector<int> numbers = {10, 25, 30, 45, 50}; // 30보다 큰 첫 번째 요소 찾기 auto it = std::find_if(numbers.begin(), numbers.end(), [](int n) { return n > 30; }); if (it != numbers.end()) { std::cout << "First number greater than 30: " << *it << std::endl; // 출력: 45 } else { std::cout << "No number greater than 30 found.\n"; } return 0;}
외부 변수 캡처를 활용한 조건 설정
#include <iostream>#include <vector>#include <algorithm> // count_ifint main() { std::vector<int> scores = {85, 92, 78, 65, 95, 80}; int min_score = 90; // 외부 변수 // min_score보다 높은 점수의 개수 세기 int count_above_min = std::count_if(scores.begin(), scores.end(), [min_score](int s) { return s >= min_score; }); std::cout << "Number of scores >= " << min_score << ": " << count_above_min << std::endl; // 출력: 2 (92, 95) return 0;}
람다의 실제 타입은 컴파일러가 생성하는 고유한 이름 없는 타입이므로, auto를 사용해야 람다 객체를 변수에 저장하거나 다른 함수로 전달할 수 있습니다.
auto와 람다의 조합 예시
#include <iostream>#include <functional> // std::function (선택적)int main() { auto my_lambda = [](int a, int b) { return a * b; }; // auto로 람다 타입 추론 std::cout << my_lambda(6, 7) << std::endl; // 출력: 42 // (참고) C++11에서는 람다를 std::function 객체로 감쌀 수 있습니다. // 이는 람다의 고유한 타입을 일반적인 함수 포인터 타입처럼 다룰 수 있게 해줍니다. std::function<int(int, int)> func_wrapper = [](int a, int b) { return a / b; }; std::cout << func_wrapper(10, 2) << std::endl; // 출력: 5 return 0;}