On this page
article
C++ Lambda
Lambda Expression (람다 표현식)
개념
- 익명의 함수 객체 생성하는 문법.
- 캡처 기능으로 지역 변수를 바인딩 가능.
- inline 혹은 constexpr
기본 문법
auto add = [](int a, int b) { return a + b; };
캡처 방식
[v1]
: 값 캡처[&v1]
: 참조 캡처[=]
: 모든 외부 변수를 값 캡처[&]
: 모든 외부 변수를 참조 캡처
Lambda Expression의 원리
- “Closure"를 만드는 표현식
- 컴파일러 동작
- 람다를 보고 그에 상응하는 함수 객체를 컴파일러가 제작
- 람다 함수 자리가 Closure Object가 됨
- Closure Object
- lambda expression이 만드는 unnamed function object
mutable lambda
- 기본적으로
operator()
는const
→ **mutable
**을 사용하면non-const
가능. - 참고로 레퍼런스를 캡쳐한 경우 어차피 레퍼런스가 아닌 레퍼런스가 가리키는 곳의 값을 바꾸는 것이라 mutable 쓰나 안쓰나 상관없음.
auto f = [v1](int a) mutable { v1 = a; };
Lambda의 타입과 함수 포인터 변환
- 모든 람다는 고유한 타입.
- 캡처 없는 람다는 함수 포인터로 변환 가능.
- 원리
- operator()와 동일한 기능을 수행하는 static member function 생성
- 변환 생성자 제공
- 원리
람다 저장 방식
auto
: 오버헤드 없음, 인라인 치환 가능.- 함수 포인터: 오버헤드 약간, 인라인 어려움.
std::function<>
: 오버헤드 있음, 다양한 호출 가능.std::function<int(int, int)> f3 = [](inta, int b) { return a + b; }
상황별 판단
- 한 개의 lambda expression을 사용할 경우 auto가 유리
- 계속 담을 것을 바꾸는 유연성 측면에선 함수 포인터나 std::function 유리
- 그러나 함수 포인터는 캡처하면 못 담고, functional의 plus같은 변환을 지원하지않는 객체는 못 담음
람다 표현식과 단위 전략
- C++버전별 차이
- 17
- 람다 표현식은 unevaluated context에서 사용될 수 없고 디폴트 생성자가 없다
- 20
- 람다 표현식은 unevaluated context에서 사용될 수 있고 캡처하지 않은 람다표현식은 디폴트 생성자가 있다
- 17
- sizeof, decltype
// C++ 20 int s1 = sizeof([](int a, int b){ return a + b; }) using T1 = decltype([](int a, int b){ return a + b; }) // C++ 11 auto lambda = [](int a, int b){ return a + b; } int s2 = sizeof(lambda); usint T2 = decltype(lambda);
Generic & Template Lambda Expressoin
Generic Lambda (C++14)
- 개념
- 람다의 인자를 auto로 적는 것
- 원리
- operator() 함수를 템플릿으로 제공하는 것
auto add = [](auto a, auto b) { return a + b; };
- 일반 함수 auto (C++20)
- 원리는 동일
auto add(auto a, auto b)
Template Lambda (C++20)
auto swap = []<typename T>(T& a, T& b) { auto tmp = a; a = b; b = tmp; };
- Generic Lambda: 타입을 자유롭게 받음.
- Template Lambda: 타입 제약 가능 (예: 같은 타입만).