티스토리 뷰

프로그래밍/C++

STL 람다표현식

에어버스 2018. 6. 10. 17:05

STL 람다표현식

익명  함수
람다 표현식 바깥 범위에 있는 변수룰 캡쳐하고 접근할 수 있다는것이 일반 함수와 다르다.
STL 알고리즘 자주 사용

람다 표현식 시작은 [] 로 표시

매개변수 지정 :

1
2
3
    auto cube = [](double val) {
        return val * val * val;
    };
cs


본문은 {} 사이에 쓰고, 일반 함수와 같다.

반환 타입을 지정하지 않으면 반환 값의 타입이 된다.

후행반환타입 형식을 사용해서 반환 타입 지정

1
2
3
    [](double val)->double {
        return val * val * val;
    };
cs

람다표현식은 익명 객체지만 변수에 람다 표현식 주소를 저장할 수 있다. (매개변수 지정 코드에서 cube 에 람다표현식 주소를 저장)

cube는 함수 포인터 처럼 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "stdafx.h"
#include <iostream>
using namespace std;
 
int main()
{
    int x{ 3 }; // x = 3
    auto cube = [](double val) {
        return val * val * val;
    };
    cout << cube(x) << endl;
    _gettch();
    return 0;
}
cs

<실행>

일반적으로 람다 표현식의 타입은 알 수 없다, 제러닉 "람다 표현식 타입" 도 없다.

람다 표현식을 함수 인수로 전달해 하는 방법

타입 매개변수가 닮다 표현식 타입이어야 하는곳에 함수를 위한 템플릿을 정의하는 것이다.
컴파일러는 항상 람다 표현식의 타입을 알고 있으므로 인수로 주어진 람다 표현식을 받는 매개젼수가 있는 함수 템플릿을 인스턴스화 할 수 있다.

data 배열의 원소 값의 제곱값을 출력한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "stdafx.h"
#include <iostream>
using namespace std;
 
template<typename ForwardIter, typename F>
void change(ForwardIter first, ForwardIter last, F fun) {
    for (auto iter = first; iter != last; iter++) {
        *iter = fun(*iter);
        cout << *iter << " ";
    }
}
int main()
{
    int data[]{ 1234 };
    change(begin(data), end(data), [](int val) { return val * val;  });
    _gettch();
    return 0;
}
cs

<실행> 

[캡처목록] (매개변수 목록) mutable -> 반환타입 { 본문 }

캡처목록 : 람다 표현식 밖에 있는 변수 목록, 변수는 값이나 참조를 캡쳐할 수 있다.

매개변수 목록 : 람다가 호출될때 람다 표현식에서 넘겨받을 매개변수 목록, 일반 함수의 인수와 같음

mutable : 값으로 캡처한 바깥 변수의 복제본을 수정 기능으로 표시하는 키워드로 생략 가능

->반환 타입 : 생략가능하며, 리턴 타입이 생략되면 반환값의 타입으로 지정한다. 반환되는 값이 없으면 void로 지정한다.

{ 본문 } : 일반 함수와 같이 람다 표현식이 실행할 내용을 정의한다.

 

[=] 
모든 자동 변수를 값으로 캡처해서 접근할 수 있다. 즉, 변수의 모든 값을 람다 표현식안에서 이용할 수 있지만, 원래 변수의 값은 변경할 수 없다. mutable 키워드를 써주면 람다 표현식 안에서 바깥 변수의 복제본을 수정할 수 있다.

람다는 람다를 실행할때 값으로 캡처한 변수의 복제보느이 로컬값을 기억해서 다음 란다 실행에 전달한다는 점에서 복제본은 사실상 static 이라 볼 수 있다.

[&]
바깥 범위의 모든 변수를 참조로 접근할 수 있다. 따라서 람다 표현식 본문에서 코드로 값을 변경할 수 있다. 이 경우에는 mutable 키워드를 쓸
필요가 없다. 저근하려는 벼누는 람다 표현식 정의 앞에만 정의되어 있으면 된다.

자신의 주소를 포함하는 변수에 접근하는 람다의 주소를 저장하는 변수 유형을 지정하기 위해 auto 를 사용할 수 없다. 이는 변수를 사용하는 표현식으로 변수를 초기화하려는 것을 의미한다.
정의되고 있는 변수를 참조하는 람다에는 auto 를 사용할 수 없다. auto는 자기 참조(Self-Reference)를 허용하지 않는다.

바깥 범위에 있는 원하는 변수만 캡처하려면 캡처절에 변수 이름만 쓰면 된다. 둘 이상인 경우 , 로 구분한다.

[=, &factor]
factor를 참조로 접근하고, 나머지 다른 변수들은 값으로 접근한다.

[&, factor]
factor를 값으로 캡처하고, 나머지 변수들은 참조로 캡처한다.
값으로캡처한 factor의 복제본을 수정하고 싶다면 mutable 키워드를 지정해야 한다.

<주의>
람다 표현식에서 바깥 범위에 있는 모든 변수를 캡처하면 실제로 그 변수를 참조하는지와 상관없이 모든 변수의 복제본을 만들어야 하므로 오버헤드가 굉장히 커질 수 있으므로 꼭 필요한 변수만 캡처하는것이 바람직 한다.

transform() 알고리즘은 인수로 전달된 함수를 원소들의 범위에서 적용할 수 있다. transform() 의 처음 두 인수는 함수 인수를 적용할 범위를 지정하는 반복자이며, 세번째 인수는 결과로 돌려줄 시작 위치를 지정하는 반복자다. 네번째 인수는 입력 범위에 적용할 함수를 지정한다. 펑터, 람다표현식, std::function 템플릿 타입을 transform() 알고리즘에 사용하는 방법 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include "stdafx.h"
#include <iostream>
#include <algorithm>
#include <iterator>
#include <functional>
using namespace std;
 
class Root {
public:
    double operator()(double x) { return sqrt(x); };
};
int main()
{
    double data[]{ 1.52.53.54.55.5 };
    Root root;
    transform(begin(data), end(data), ostream_iterator<double>(cout" "), [](double x) {return x * x*x; });
    cout << endl;
    function<double(double)> op{ [](double x) {return x * x; } };
    cout << endl;
    transform(begin(data), end(data), ostream_iterator<double>(cout" "), op);
    cout << endl;
    transform(begin(data), end(data), ostream_iterator<double>(cout" "), [&op](double x) {return op(x)*op(x); });
    _gettch();
    return 0;
}
cs

<실행>

네번째 transform() 알고리즘 출력의 목적지는 데이터를 출력 스트림에 쓰는 출력 스트림 반복자로 지정한다. ostream_iterator 생성자의 두번째 인수는 각 값 뒤에 쓸 구분자를 지정한다.

첫번째 transform() 호출은 마지막 인수로 Root 객체를 전달한다. Root 클래스는 인수의 제곱근을 반환하는 operator()()멤버를 정의했다. 두번째 transorm() 호출은 입력값의 세제곱을 계산하는 람다 표현식을 인수로 작성한 것이다. 세번쩨 transorm() 호출은 funtion 타입 템플릿이 동작하는 것을 보여준다. 네번째 transorm() 호출은 람다 함수가 다른 람다 함수를 호출하는 것을 보여준다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/06   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30