transform과 for_each 함수를 공부하다 람다식을 사용하는 것을 보고 정리를 해보게 되었다.
참고한 문서는 아래와 같다
https://learn.microsoft.com/ko-kr/cpp/cpp/lambda-expressions-in-cpp?view=msvc-170
C++ 람다 식
자세한 정보: C++의 람다 식
learn.microsoft.com
씹어먹는 C++ 토막글 ② - 람다(lambda) 함수
모두의 코드 씹어먹는 C++ 토막글 ② - 람다(lambda) 함수 작성일 : 2013-01-08 이 글은 99270 번 읽혔습니다. 이 글은 http://ciere.com/cppnow12/lambda.pdf 에서 가져왔고 한국말로 번역되었습니다. 또한 저의 개
modoocode.com
https://en.cppreference.com/w/cpp/language/lambda
Lambda expressions (since C++11) - cppreference.com
Constructs a closure (an unnamed function object capable of capturing variables in scope). [edit] Syntax [edit] Lambda expressions without an explicit template parameter list (possibly non-generic) [captures ] front-attr (optional) (params )
en.cppreference.com
1. 람다식이 무엇일까?
- C++ 11에 도입되었으며, 이름이 없는 함수이다.
- 함수에 인수로 호출되거나 전달되는 위치에서 함수 개체를 정의하는 편리한 방법이다.
- 코드의 가독성을 높이고, 유연한 처리가 가능하도록 해준다.
- 간단한 sort 함수에서의 사용 예제를 보면서 이해해 보자
void abssort(float* x, unsigned n)
{
sort(x, x + n, [](float a, float b) {return abs(a) < abs(b); });
}
- 위의 코드에 float arr[3] = { 1.2f,-5.4f,0.2f }; 를 대입하면, {0.2, 1.2, -5.4} 로 정렬되는 결과가 나온다.
2. 기본 구조
- capture절
- 값에 의한 캡쳐인지, 참조에 의한 것인지 지정하기
- [ ] : 람다 본문이 바깥 범위 변수에 엑세스하지 않음
- [&] : 외부의 모든 변수를 레퍼런스로 가져온다.
- [=] : 외부의 모든 변수들을 값으로 가져온다,
- 값으로 가져오는 경우 해당 변수들은 자동으로 const 키워드가 붙는다
- ex) total은 레퍼런스로, factor는 값으로 엑세스 하는 것을 아래와 같이 여러가지로 표현이 가능하다.
- [&total, factor]
- [factor, &total]
- [=, &total]
- [&, factor]
- 값에 의한 캡쳐인지, 참조에 의한 것인지 지정하기
- 매개변수 목록
- 변경 가능한 사양 (선택)
- 일반적으로 람다의 호출 연산자는 const-by-value 이지만, mutable을 통해 취소할 수 있다.
- mutable을 통해 람다 본문에서 값으로 캡쳐된 변수를 수정할 수 있다.
- exception-specification (선택)
- noexcept를 사용하여 람다식이 throw 하지 않음을 나타내도록 할 수 있다.
- 후행 반환 형식 (선택)
- 반환 형식은 원래 자동으로 추론된다.
- 반환 형식을 auto로 지정하지 않는 한 해당 키워드를 사용할 필요가 없다
- 람다 본문에 return 문이 하나만 포함된 경우 반환 형식을 생략할 수 있다.
- 람다 본문
- 람다 본문에서 접근할 수 있는 변수는
- 바깥족 범위에서 캡쳐된 변수
- 매개변수
- 로컬로 선언된 변수
- 전역변수
- 람다 본문에서 접근할 수 있는 변수는
3. 예제들
- 다른 캡쳐 방식, mutable 키워드, 매개변수 사용
- mutable 키워드를 통해 값으로 캡쳐된 n 이라는 값을 람다 본문에서 수정할 수 있게 해줌
- 그러나 레퍼런스로 캡쳐된 값인 sum만 값이 변경되는 것을 확인할 수 있다.
int sum = 0;
int n = 0;
[&, n](int a) mutable {sum = ++n + a; }(4);
cout << sum << " " << n << "\n"; //5 0 출력
- 레퍼런스 인자로 받기
int i = 7;
[](int& v) {v *= 10; }(i);
cout << i << "\n"; //70 출력
- 캡쳐가 이루어지는 시점은 함수 객체(클로저)가 처음 생성될 때이다.
int num = 10;
auto func = [=]{cout << num << "\n";};
num = 100;
func(); //10 출력
- 벡터와 string 값 바꾸기
- 기억할 것
- 람다를 정의하고 바로 실행하려면, 뒤에 ( )를 붙여야 한다.
- 매개변수가 있다면 ( ) 안에 우리가 지정한 매개변수를 넣으면 된다.
- 기억할 것
vector<int> vec = { 1,2,3,4,5 };
[&] (int a) {vec[0] = a; }(100);
for (auto v : vec)
cout << v << " "; //100 2 3 4 5 출력
string str = "Hello";
for_each(str.begin(), str.end(), [&](char& c) {c = toupper(c); });
cout << str; //HELLO 출력
- 약간 복잡한 예제 (캡쳐의 범위에 관한)
- 기억할 것
- 람다를 변수로 저장한 후 호출하는 모습 -> m(); f();
- mutable을 통해 값으로 캡쳐한 i 값을 수정하게 함
- 기억할 것
int i = 8;
auto f = [i]() mutable {
int j = 2;
auto m = [&, j]() mutable { i /= j; };
m();
cout << "inner: " << i; //4출력
};
f();
cout << " outer: " << i; //8출력
'C++' 카테고리의 다른 글
C++ 디자인 패턴 (0) | 2025.01.06 |
---|---|
C++ TIL day 13 (1) | 2025.01.03 |
C++ TIL day 12 (1) | 2025.01.02 |
C++ TIL day 11 (포인터 연산 문제) (1) | 2024.12.31 |
const 키워드 (0) | 2024.12.31 |