📒 C++ - lambda
📌 lambda란?
- 익명 함수 객체를 편리하게 정의할 수 있다.
- 알고리즘 또는 비동기 함수에 전달되는 코드를 캡슐화하는 데에 사용된다.
📌 lambda의 형태
[capture](return type)
{
source code
}();
capture : 람다 스코프 외부에서 어떠한 변수를 가져오는 것.
#include <iostream>
int main()
{
int value = 10;
auto func = [value]()
{
value = 20;
};
}
- 캡처된 변수를 수정하게 되면 함수를 실행할 때마다 결괏값이 변경되기 때문에 기본값이 const이다.
- 참조로 받게 되면 값은 변경이 가능하다. 왜냐하면 캡처의 주소를 바꾸는 것이 아니라 값만 바꾸는 것은 함수 객체에 변함은 없기 때문이다.
- mutable 키워드를 활용하여 값을 변경할 수 있다.
#include <iostream>
int main()
{
int value = 10;
auto func = [value]() mutable
{
value = 20;
std::cout << value << std::endl;
};
std::cout << value << std::endl;
func();
}
Output:
20
10
mutable : const 함수에서 멤버 변수의 값을 수정할 수 있게 한다.
📌 capture
int num0 = 10;
int num1 = 20;
auto func = [=] ()
{
reutrn num0 + num1;
};
auto func = [&] ()
{
reutrn num0 + num1;
};
auto func = [&, num0]()
{
return num0 + num1;
};
auto func = [=, &num0]()
{
return num0 + num1;
};
#include <iostream>
auto func()
{
int num = 10;
return [&]
{
return num;
};
}
int main()
{
auto f = func();
std::cout << f() << std::endl;
}
- 값이 제대로 제대로 나올 수도 있고, 안 나올 수도 있다.
- 레퍼런스로 캡쳐하면 자동 지역변수이기 때문에 스택에서 사라질 수 있다.
#include <iostream>
struct Test
{
int num = 10;
auto func()
{
return [=]
{
return num;
};
}
};
int main()
{
Test* t = new Test;
auto func = t->func();
delete t;
std::cout << func() << std::endl;
}
Output:
-572662307
- 값으로 캡쳐된 것처럼 보이지만, 사실상 this가 캡처된 것이다.
- 아래 예시로 해결할 수 있다.
#include <iostream>
struct Test
{
int num = 10;
auto func()
{
return [num = num]
{
return num;
};
}
};
int main()
{
Test* t = new Test;
auto func = t->func();
delete t;
std::cout << func() << std::endl;
}
- initialize capture를 활용하면 값으로 캡처할 수 있다.
- C++14 이상에서 사용할 수 있다.
- C++11이라면 func() 함수 안에서 temp 변수를 따로 만들어서 넘겨주어야 한다.
- *this를 활용할 수도 있지만 this 전체가 복사되는 것이기 때문에 바람직하지 않아 보인다.
📌 Generic lambda(C++14 이상)
#include <iostream>
int main()
{
auto func = [](auto value)
{
return value;
};
std::cout << func(10) << std::endl;
std::cout << func("A") << std::endl;
}
Output:
10
A
- auto이기 때문에 initiallize list는 불가능하다.
📌 Generic lambda(C++20 이상)
#include <iostream>
int main()
{
auto func = []<typename T>(T value)
{
return value;
};
std::cout << func(10) << std::endl;
std::cout << func("10") << std::endl;
}
Output:
10
A