[모던C++입문] 3.9 람다
- 📕 Book/모던C++입문
- 2021. 7. 15.
3.9 람다(Lamda) (c++11)
//함수를 인수로 즉시 전달할 수 있다
fin_diff([](double x) {return sin(x) + cos(x);}, 1., 0.001)
//람다 표현식을 재사용하기 위해 변수에 저장할 수도 있다.
auto sc_l = [](double x) { return sin(x) + cos(x); }
//리턴타입을 명시적으로 선언하고자 한다면
[](double x) -> double { return sin(x) + cos(x); }
캡처
- 람다 표현식은 자체 매개변수 또는 이전에 캡처된 매개변수만 사용 가능
//람다를 매개변수화 할때 단순한 연산을 삽입 가능하나
//매개변수가 많을때는 생산적이지 못함
a = fin_diff([]double x) {return sin(2.5*x);, 1., 0.001);
b = fin_diff([]double x) {return sin(3.0*x);, 1., 0.001);
c = fin_diff([]double x) {return sin(3.5*x);, 1., 0.001);
//다음과 같은 상황에서는 변수나 상수에 접근이 불가
double phi = 2.5;
auto sin_phi = [](double x) { return sin(phi * x); }; //오류
값에 의한 캡처
- 람다를 호출할 시점의 값을 사용
- 캡처된 변수는 const 한정된 operator와 같기에 변경할 수 없다
//람다에서 phi 변수를 사용하려면 캡쳐를 해야한다
double phi = 2.5;
auto sin_phi = [phi](double x) { return sin(phi * x); };
//여러 변수를 캡처하고 싶다면 쉼표로 구분
double xi = 0.2;
auto sin2 = [phi, xi](double x){ return sin(phi * x) + cos(x) * xi; };
//sin2 를 펑터 클래스로 작성한다면
struct lambda_f
{
lambda_f(double phi, double xi) : phi(phi), xi(xi) {}
double operator(){double x) const
{
return sin(phi * x) + cos(x) * xi;
}
const double phi, xi;
};
phi = 2.5; xi = 0.2;
auto px = [phi, xi](double x) { return sin(phi * x) + cos(x) * xi; };
phi = 3.5; xi = 1.2;
a = fin_diff(px, 1., 0.001); //여전히 phi=2.5, xi = 0.2이다
auto l_inc = [phi](double x) { phi += 0.6; return phi; }; //오류
//캡처된 값을 수정하려면 람다를 mutable로 한정해야 한다.
auto l_mut = [phi](double x) mutable { phi += 0.6; return phi; };
레퍼런스에 의한 캡처
- 변수를 레퍼런스로 캡처할 수도 있다.
phi = 2.5; xi = 0.2;
auto px = [&phi, &xi](double x) { return sin(phi * x) + cos(x) * xi; };
phi = 3.5; xi = 1.2;
a = fin_diff(px, 1., 0.001); //이제는 phi=3.5, xi = 1.2이다
- [=] : 복사를 통해 모든 변수를 캡처
- [&] : 레퍼런스를 통해 모든 변수를 캡처
- [=, &a, &b, &c] : 복사를 통해 모든 변수를 캡처하되 a,b,c는 레퍼런스를 통해 캡처
- [&, a, b, c] : 레퍼런스를 통해 모든 변수를 캡처하되 a,b,c는 복사를 통해 캡처
- 그러나 모든 변수를 캡처하는 기능은 부실 레퍼런스의 위험을 증가시키고
- 정적 변수나 멤버 변수를 무시한다.
일반화된 캡처
- 캡처의 일반화는 일반화된 캡처(Init Capture)를 통해 이루어진다.
- 일반화된 캡처는 변수를 클로저로 옮기고 새로운 이름을 부여할 수 있다.
auto F = make_uniqu<Mat>(Mat{ {1., 0.5}, {0.5, 1./3.} });
//unique_ptr은 복사할수 없으므로 클로저가 소유할수 있게 옮겨야한다.
auto apply_hilbert = [F = move(F)](const Vec& x) { return Vec(*F * x); };
int x = 4;
auto y = [&r = x, x = x + 1]()
{
r += 2; //x = 6
return x + 2; //여기서 x = x+1 = 5이고 따라서 7을 반환
}();
cout << x << endl;
cout << y << endl;
cout << x << endl;
//6 7 6 이 출력됨
auto y = [&r = x, x = r + 1] {}; //오류 : 컨텍스트에 r이 없음
제네릭 람다 (C++14)
- auto 키워드를 사용함으로 리턴 타입을 명시적으로 선언하지 않아도 된다.
template<typename T
void reverse_sort(T& c)
{
sort(begin(c), end(c), [](auto x, auto y) { return x > y); });
}
반응형