들어가며
이번 포스트에서는 람다의 다양한 로컬 변수 캡처 방법에 대해 살펴 볼 것이다. C++ 람다에 대한 추가 정보는 이전 포스트
들을 참고 하도록 하자.
디폴트 캡처
디폴트 캡쳐는 모든 지역 변수에 대해 일괄 캡쳐를 진행할 수 있는 캡쳐 연산자다. 기본적인 람다 인트로듀서(대괄호로 표현된 람다 제일 시작 부분)에 캡쳐 리스트를 적는 대신 '=' 또는 '&'를 적는다.
기호 | 동작 |
[=] | 모든 지역 변수를 capture by value |
[&] | 모든 지역 변수를 capture by reference |
int v1 = 10, v2 = 20;
auto f1 = [=]() {}; // 모든 로컬 변수를 값으로 캡쳐
auto f2 = [&]() {}; // 모든 로컬 변수를 참조로 캡쳐
'=' 의 경우 모든 지역 변수를 값을 캡쳐 하겠다는 의미이고, '&'는 모든 지역 변수를 참조로 캡쳐 하겠다는 의미다.
'=', '&' 외에도 개별 변수들을 추가 캡쳐 함으로써 예외를 처리를 할 수도 있다.
auto f3 = [=, &v1]() {}; // 모든 로컬 변수를 값으로 캡쳐하지만 v1은 참조로 캡쳐
auto f4 = [&, v1]() {}; // 모든 로컬 변수를 참조로 캡쳐하지만 v1은 값으로 캡쳐
auto f5 = [&, &v1]() {}; // 디폴트 참조에 참조 예외 시도. 컴파일 에러
캡쳐된 변수의 이름 변경
람다는 단순히 로컬 변수를 캡쳐하는 것 뿐만 아니라 가독성을 위해 캡쳐된 로컬 변수의 이름을 변경하여 사용할 수도 있다.
auto f6 = [x = v1, &y = v2](int a) { y = a + x; };
위 코드는 v1은 값을 캡쳐하되, 람다 내에서 x라는 이름으로 사용되고, v2는 참조로 캡처하되 y라는 이름으로 람다 내에서 사용 됨을 의미한다.
move를 통한 캡쳐
람다의 캡처는 단순히 복사만 가능한 것이 아니라 move 또한 가능하다.
std::string s = "Hello world";
auto f7 = [msg = std::move(s)] () {};
std::cout << s << std::endl; // move 되어 자원을 뺏겼으므로 빈 문자열 출력 됨
마치며
이상 람다에서 로컬 변수를 캡처하는 다양한 방법에 대해 살펴 보았다. 정리하면 =, & 처럼 전체 로컬 변수를 대상으로 캡처를 할 수 있으며, 각 개별 변수들을 별도 리스팅하면서 예외를 줄 수 있다는 것이다. 어려운 내용이 아니므로 간단하게 정리하고 넘어 가도록 하자.
다음 포스트(람다와 함수 포인터)에서는 람다를 함수 포인터에 저장해서 쓰는 방법과 제약 사항, 그리고 원리에 대해서 살펴 보도록 하겠다.