함수 객체
함수 객체의 개념
함수 객체(Function Object) 또는 함수자(Functor)는 함수처럼 동작하는 객체를 말합니다.
C++에서는 operator()
연산자를 오버로딩하여 함수 객체를 구현합니다.
함수 객체의 주요 특징
- 함수처럼 호출 가능
- 상태를 가질 수 있음
- 컴파일 시간에 타입 체크 가능
- 인라인화 가능
- STL 알고리즘과 함께 사용 가능
함수 객체의 기본 구현
다음은 간단한 함수 객체의 예입니다.
#include <iostream>
class Adder {
public:
int operator()(int a, int b) const {
return a + b;
}
};
int main() {
Adder add;
std::cout << add(3, 4) << std::endl; // 출력: 7
return 0;
}
이 예제에서 Adder
클래스는 operator()
를 오버로딩하여 함수 객체로 동작합니다.
함수 객체와 STL 알고리즘
STL 알고리즘은 함수 객체를 인자로 받아 유연한 동작을 구현할 수 있습니다.
다음은 std::count_if
알고리즘과 함수 객체를 사용하는 예입니다.
#include <iostream>
#include <vector>
#include <algorithm>
class IsEven {
public:
bool operator()(int n) const {
return n % 2 == 0;
}
};
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int count = std::count_if(vec.begin(), vec.end(), IsEven());
std::cout << "Number of even elements: " << count << std::endl;
return 0;
}
상태를 가진 함수 객체
함수 객체의 강점 중 하나는 내부 상태를 가질 수 있다는 점입니다.
이를 통해 호출 간에 정보를 유지할 수 있습니다.
#include <iostream>
class Accumulator {
private:
int sum;
public:
Accumulator() : sum(0) {}
int operator()(int n) {
return sum += n;
}
int getSum() const { return sum; }
};
int main() {
Accumulator acc;
std::cout << acc(10) << std::endl; // 10
std::cout << acc(20) << std::endl; // 30
std::cout << acc(30) << std::endl; // 60
std::cout << "Final sum: " << acc.getSum() << std::endl; // 60
return 0;
}
템플릿을 이용한 일반화된 함수 객체
템플릿을 사용하면 다양한 타입에 대해 동작하는 함수 객체를 만들 수 있습니다.
#include <iostream>
#include <string>
template<typename T>
class Less {
public:
bool operator()(const T& a, const T& b) const {
return a < b;
}
};
int main() {
Less<int> lessInt;
std::cout << "3 < 5: " << lessInt(3, 5) << std::endl; // 1 (true)
Less<std::string> lessString;
std::cout << "apple < banana: " << lessString("apple", "banana") << std::endl; // 1 (true)
return 0;
}
바인더와 어댑터
STL은 함수 객체를 변형하거나 조합하는 도구를 제공합니다.
std::bind
std::bind
를 사용하여 함수의 인자를 부분적으로 고정할 수 있습니다.
#include <iostream>
#include <functional>
int multiply(int a, int b) {
return a * b;
}
int main() {
auto times2 = std::bind(multiply, std::placeholders::_1, 2);
std::cout << "4 * 2 = " << times2(4) << std::endl; // 8
auto always42 = std::bind(multiply, 6, 7);
std::cout << "6 * 7 = " << always42() << std::endl; // 42
return 0;
}
std::not_fn
std::not_fn
을 사용하여 조건을 반전시킬 수 있습니다.
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
bool isEven(int n) {
return n % 2 == 0;
}
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
auto isOdd = std::not_fn(isEven);
int count = std::count_if(vec.begin(), vec.end(), isOdd);
std::cout << "Number of odd elements: " << count << std::endl;
return 0;
}
람다 표현식과 함수 객체
C++ 11부터 도입된 람다 표현식은 익명 함수 객체를 쉽게 만들 수 있게 해줍니다.
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
std::for_each(vec.begin(), vec.end(), [](int& n) { n *= 2; });
std::cout << "Doubled values: ";
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
람다 표현식은 내부적으로 함수 객체로 변환됩니다.
실습 : 사용자 정의 정렬 기준
다음 요구사항을 만족하는 프로그램을 작성해보세요.
Person
구조체 정의 (이름, 나이)- 여러
Person
객체를 벡터에 저장 - 나이를 기준으로 정렬하는 함수 객체 구현
- 이름을 기준으로 정렬하는 람다 표현식 작성
- 두 가지 방법으로 벡터 정렬 및 결과 출력
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
struct Person {
std::string name;
int age;
Person(const std::string& n, int a) : name(n), age(a) {}
};
class AgeComparator {
public:
bool operator()(const Person& a, const Person& b) const {
return a.age < b.age;
}
};
int main() {
std::vector<Person> people = {
{"Alice", 30}, {"Bob", 25}, {"Charlie", 35}, {"David", 28}
};
// 나이 기준 정렬
std::sort(people.begin(), people.end(), AgeComparator());
std::cout << "Sorted by age:" << std::endl;
for (const auto& person : people) {
std::cout << person.name << ": " << person.age << std::endl;
}
// 이름 기준 정렬
std::sort(people.begin(), people.end(),
[](const Person& a, const Person& b) { return a.name < b.name; });
std::cout << "\nSorted by name:" << std::endl;
for (const auto& person : people) {
std::cout << person.name << ": " << person.age << std::endl;
}
return 0;
}
연습 문제
std::transform
과 함수 객체를 사용하여 벡터의 모든 요소를 제곱하는 프로그램을 작성하세요.- 람다 표현식을 사용하여
std::remove_if
로 벡터에서 특정 조건을 만족하는 요소를 제거하는 프로그램을 작성하세요. - 함수 객체를 사용하여
std::sort
로 벡터를 내림차순으로 정렬하는 프로그램을 작성하세요.
참고자료
- "Effective STL" by Scott Meyers (항목 38-42 : 함수자에 대한 내용)
- C++ Reference : Function objects
- "Modern C++ Design" by Andrei Alexandrescu (Chapter 5 : Generalized Functors)
- "C++ Templates : The Complete Guide" by David Vandevoorde and Nicolai M. Josuttis (Chapter 22: Bridging Static and Dynamic Polymorphism)
- "Functional Programming in C++" by Ivan Čukić