[Basic C++] #47_함수 객체
STL 알고리즘 중 "함수 객체"에 대해 알아보겠습니다.
"전문가를 위한 C"의 17 항목, "STL 알고리즘 마스터하기"에 해당하는 내용입니다.
Overview
- 개념
- 산술 함수 객체
- 비교 함수 객체
- 논리 함수 객체
- 구조체 오버로딩
- 람다 함수 객체
#0. 개념
1. 개념
- 함수 객체는 함수처럼 동작하는 객체를 의미합니다. C++에서는 주로 Predicate를 표현하거나, 콜백 함수로 활용합니다.
- <functional> 헤더에 정의된 여러 함수 객체 클래스들을 활용하여 "콜백" 작업을 수행할 수 있습니다.
#1. 산술 함수 객체
1. 코드
#include <iostream>
#include <vector>
#include <numeric>
#include <functional>
using namespace std;
int main()
{
vector<int> v{ 1, 2, 3, 4, 5 };
// multiplies< /* typename 생략 */ >() : 투과적 함수 객체 연산자 사용
int res = accumulate(cbegin(v), cend(v), 0, multiplies<>());
cout << res << endl;
}
Details
- C++ 다섯 가지 이항 연산자에 함수 객체 템플릿을 제공합니다 - plus, minus, multiplies, divides, modulus.
- 간단하게 "operator+" 등을 사용할 수 있지만, 함수 객체를 사용하여 알고리즘에 콜백으로 전달할 수 있기 때문입니다!
#2. 비교 함수 객체
1. 코드
#include <iostream>
#include <queue>
#include <functional>
using namespace std;
int main()
{
// 디폴트 비교 연산 less<>() 에서 greater<>()로 변경
priority_queue<int, vector<int>, greater<>> q;
q.push(3);
q.push(4);
q.push(5);
q.push(6);
q.push(7);
while (!q.empty())
{
cout << q.top() << " ";
q.pop();
}
}
Details
- 산술 함수 객체와 더불어 C++는 비교 함수 객체 클래스 또한 제공하고 있습니다 - equal_to, not_equal_to, greater, less_equal, greater_equal.
- 위 코드 예제는 "priority_queue"의 디폴트 정렬 순서 "오름차순(less)"에서 "내림차순(greater)"로 변경하고 있습니다.
#3. 논리 함수 객체
1. 코드
#include <iostream>
#include <vector>
#include <numeric>
#include <functional>
using namespace std;
int main()
{
vector<bool> v{ true, false, true, false };
auto res = accumulate(cbegin(v), cend(v), true, logical_and<>());
cout << res << endl;
}
Details
- C++는 세 가지 논리 함수 객체 또한 제공합니다 - logical_or, logical_and, logical_not.
#4. 구조체 오버로딩
1. 예제-1
#include <iostream>
#include <queue>
struct CompareLength {
bool operator()(const std::string& str1, const std::string& str2) const {
return str1.length() < str2.length();
}
};
int main() {
std::priority_queue<std::string, std::vector<std::string>, CompareLength> pq;
pq.push("apple");
pq.push("banana");
pq.push("cherry");
pq.push("date");
while (!pq.empty()) {
std::cout << pq.top() << std::endl;
pq.pop();
}
return 0;
}
Details
- 구조체 오버로딩을 활용하는 대표적인 예제는 C++의 priority_queue(우선순위 큐) 선언 시 함수 객체로 사용하는 방법입니다.
2. 예제-2
#include <iostream>
#include <algorithm>
#include <vector>
struct GreaterThan {
bool operator()(int a, int b) const {
return a > b;
}
};
int main() {
std::vector<int> numbers = {5, 2, 9, 1, 5, 6};
std::sort(numbers.begin(), numbers.end(), GreaterThan());
for (int num : numbers) {
std::cout << num << " ";
}
return 0;
}
Details
- Predicate은 알고리즘 함수나 컨테이너의 멤버 함수와 함께 사용되는 함수 혹은 함수 객체입니다.
- sort 알고리즘은 선택적으로 Predicate을 인자로 전달해, 그 정렬 방식을 정의할 수 있습니다.
- 이때, 구조체 오버로딩 방식을 통해 Predicate을 정의할 수 있습니다.
#5. 람다 함수 객체
1. 예제-1
#include <iostream>
#include <queue>
#include <string>
#include <functional>
using namespace std;
int main() {
auto Predicate = [](const string& a, const string& b) {return a > b; };
// #1. decltype 활용
priority_queue<string, vector<string>, decltype(Predicate) > pq;
// #2. std::function 활용
priority_queue < string, vector<string>, function<bool(const string& a, const string& b)>> pq2(Predicate);
pq.push("apple");
pq.push("banana");
pq.push("cherry");
pq.push("date");
while (!pq.empty()) {
std::cout << pq.top() << std::endl;
pq.pop();
}
return 0;
}
Details
- 우선 순위 큐 선언 시 필요한 Predicate를 람다 함수를 통해 정의할 수 있습니다.
- 첫 번째 우선순위 큐 선언 방법은 decltype을 활용합니다. decltype은 함수나 표현식의 결과 유형을 컴파일 시간에 추론하는 키워드입니다. 주로 템플릿 프로그래밍에서 복잡한 유형을 추론할 때 주로 사용됩니다.
- 두 번째 우선순위 큐 선언 방법은 std::funciton을 활용합니다. std::function은 호출 가능한 어떠한 유형의 객체도 래핑 할 수 있는 템플릿 클래스입니다.
2. 예제-2
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
auto Predicate = [](const int& a, const int& b) {return a < b; };
vector<int> v = { 1,5,7,9,3,2,15 };
sort(begin(v), end(v), Predicate);
return 0;
}
Details
- sort 함수 호출 시 람다 함수로 정의한 함수 객체를 Predicate로 전달할 수 있습니다.
'언어 > Basic C++' 카테고리의 다른 글
[Basic C++] #49_STL 알고리즘, 불변 순차 알고리즘 (0) | 2022.07.13 |
---|---|
[Basic C++] #48_함수 객체 어댑터, 바인더, not1(), not2(), mem_fn() (0) | 2022.07.09 |
[Basic C++] #46_람다 표현식과 STL 알고리즘 (0) | 2022.07.07 |
[Basic C++] #45_람다 표현식 활용, 제네릭 람다 표현식, 람다 캡처 표현식, 리턴 타입으로서 람다 표현식 (0) | 2022.07.06 |
[Basic C++] #44_람다 표현식, 기본 (0) | 2022.07.05 |