알고리즘 STL 의 함수 중 일부는 연산?을 매개 변수로 하여 인자를 전달 받아 실행된다.
e.g. sort(first, last, predicate) 에서 predicate 은 정렬의 기준이 되는 boolean 반환 타입의 함수이다.
이러한 STL 함수를 커스터마이즈 하기 위해 필요한 연산은 간단한 일회성인 경우가 많은데,
이 연산을 개별적인 함수로 정의하는 것 대신에 필요한 위치에서 '익명'의 함수 객체로 정의하여 사용하는 방식이 '람다' 함수 이다. 여러 가지 표현 방식이 있는데, 그 중 가장 간단한 방식으로 살펴보고자 한다.
(어차피 코드 가독성을 위해 간단한 연산 위주로 사용해야 한다.)
람다 표현식 / 람다식 / 람다 함수
[capture](parameters) -> return_type {
// operation
}
- capture: 람다 표현식 외부의 변수를 값 또는 참조로 캡쳐하여 내부에서 사용 가능하다.
- parameters: 연산에 필요한 매개 변수 선언
- return type: 반환할 자료형 - 보통 컴파일러가 추론하므로 생략 가능 (복잡한 컨디셔널 등이 있는 경우 명시해야 하지만, 그런 거라면 개별 함수로 정의하는 게 낫겠지?)
아래는 내림차순 정렬을 위해 sort() 함수에 람다 표현식을 인자로 전달하는 예시
sort(v.begin(), v.end(), [](int a, int b) {
return a > b;
});
아래는 값 vs. 참조로 캡쳐 시 캡쳐된 변수의 값 차이
int x = 10;
auto addValue = [x]() { // 값으로 캡처
return x + 5;
};
auto addReference = [&x]() { // 참조로 캡처
return x + 5;
};
x = 20; // x 값 변경
std::cout << "addValue: " << addValue() << std::endl; // 15
std::cout << "addReference: " << addReference() << std::endl; // 25
- 값으로 캡쳐 : 변수의 값이 addValue 할당 시점에 복사되어 정의된다.
- 참조로 캡쳐 : 변수가 참조이므로 addReference 호출 시점에 x 값이 사용된다.
std::accumulate()
https://en.cppreference.com/w/cpp/algorithm/accumulate
std::accumulate - cppreference.com
template< class InputIt, class T > T accumulate( InputIt first, InputIt last, T init ); (1) (constexpr since C++20) template< class InputIt, class T, class BinaryOp > T accumulate( InputIt first, InputIt last, T init, BinaryOp op ); (2) (constexpr since C+
en.cppreference.com
포맷
1)
template< class InputIt, class T >
T accumulate( InputIt first, InputIt last, T init );
[first, last) 범위의 원소들과 init 값의 합계 반환
2)
template< class InputIt, class T, class BinaryOp >
T accumulate( InputIt first, InputIt last, T init, BinaryOp op );
init 부터 시작해서 [first, last) 범위의 원소들에 대해 차례로 op 연산을 반복해 나간 결과 반환
2번 형식의 예를 위 람다 표현식을 활용해 아래와 같이 살펴볼 수 있다.
vector<int> v{1, 2, 3, 4, 5};
auto dash_fold = [](sstring a, int b) {
return a + '-' + to_string(b);
}
string s = accumulate(++v.begin(), v.end(), to_string(v[0]), dash_fold);
cout << s;
// output : 1-2-3-4-5
v[0] 부터 시작해서 dash_fold 연산을 v 의 원소에 대해 순차적으로 해 나간 결과 값을 반환한 것이다.
std::transform()
https://en.cppreference.com/w/cpp/algorithm/transform
std::transform - cppreference.com
template< class InputIt, class OutputIt, class UnaryOp > OutputIt transform( InputIt first1, InputIt last1, OutputIt d_first, UnaryOp unary_op ); (1) (constexpr since C++20) template< class ExecutionPolicy, clas
en.cppreference.com
transform(input_first, input_last, output_first, operation)
transform(input1_first, input1_last, input2_first, output_first, operation)
주어진 입력 범위에 대해 주어진 함수를 실행하고 그 결과를 출력 범위에 저장한다.
두 번째 형식의 경우 input1 과 input2 에 대해 함수를 실행한다. (input1 이 지정한 길이 기준)
아래는 정수 배열을 받아 각 정수의 제곱을 반환하도록 사용한 예시
vector<int> v = {1, 2, 3, 4, 5};
vector<int> v2(v.size());
transform(v.begin(), v.end(), v2.begin(), [](int x) {
return x*x;
});
// v2 = {1, 4, 9, 16, 25}
이것 역시 람다 표현식 사용하여 transform 호출 시 함수를 인자로 넘겨줄 수 있다.
std::partition()
https://en.cppreference.com/w/cpp/algorithm/partition
std::partition - cppreference.com
template< class ForwardIt, class UnaryPred > ForwardIt partition( ForwardIt first, ForwardIt last, UnaryPred p ); (1) (constexpr since C++20) template< class ExecutionPolicy, class ForwardIt, class UnaryPred > ForwardIt partition( ExecutionPolicy&& policy,
en.cppreference.com
partition(first, last, predicate)
[first, last) 범위의 원소에 대해 predicate 이 반환하는 bool 값에 따라 true 인 원소들이 먼저 오도록 재정렬하고, false 그룹의 첫 원소를 가리키는 반복자를 반환한다.
*나뉠 때 순서가 보존되지 않는다.
vector<int> v = {1, 2, 3, 4, 5};
partition(v.begin(), v.end(), [](int x) {
return x % 2 == 0;
});
짝수가 먼저 오고 이후에 홀수가 오도록 분할된다. 역시 predicate을 인자로 넘길 때 람다표현식을 이용할 수 있다.