함수 객체( function object )
함수 객체( function object )는 operator() 함수를 구현한 타입( type )을 말합니다.
C++ 표준 라이브러리에서는, 펑터( functor )라고도 불리는, 이 타입을 주로 컨테이너나 알고리즘의 정렬 기준이 필요할 때 사용합니다.
다음 예제에서는 이러한 함수 객체를 사용하는 법을 볼 수 있습니다.
class FuncObj{
public:
int operator()(int a, int b){ // 이 연산자를 구현한 타입이 함수 객체
return a + b;
}
};
int Func(int a, int b){ // 일반 함수
return a + b;
}
int main(){
FuncObj func; // 함수 객체의 변수 선언
int a = 5;
int b = 6;
int sum1 = func(a, b); // operator()를 호출
int sum2 = Func(a, b); // 일반 함수 호출
}
위에서 보듯이, 함수 객체의 변수명 func와 ()를 사용해서, 이 func 객체의 operator()를 호출할 수 있습니다.
이것이 일반 함수를 사용하는 법과 유사하기 때문에, FuncObj 타입을 함수 객체라고 부르는 이유입니다.
( 참고로, 일반 함수를 호출할 때도, () 연산자의 피연산자로 함수명을 사용합니다. )
그렇지만, 일반 함수보다 이러한 함수 객체( function object )를 사용할 때는 다음과 같은 장점이 있습니다.
첫 번째, 함수 객체는 상태 정보를 담을 수 있습니다.
두 번째, 함수 객체는 타입( type )이므로, 템플릿의 매개 변수가 될 수 있습니다.
함수 객체의 상태 정보
다음 예문은 배열의 원소들의 값을 3씩 증가시키는 코드입니다.
#include <algorithm>
using namespace std;
int increment(int n){ // transform에 전달될 함수
return n + 3;
}
int main(){
int arr[] = {1, 2, 3, 4, 5};
int n = sizeof(arr)/sizeof(arr[0]);
int res[n];
std::transform(arr, arr+n, res, increment);
for (int x : res){
cout << x << " ";
}
return 0;
}
여기에 쓰인 std::transform 함수는 arr 배열의 처음부터 끝까지의 원소를 대상으로 increment 함수를 호출하여, 그 결과를 res 배열에 저장하는 함수입니다.
그런데, 이 increment 함수는 매개 변수를 하나밖에 사용하지 않습니다.
왜냐하면, transform이 매개 변수를 하나만 갖는 함수를 필요로 하기 때문입니다.
그래서, 만약 배열의 원소에 3 대신 5를 더하고 싶다면, increment 함수를 다시 작성해야 합니다.
아니면, 전역 변수를 사용해서 추가적인 정보를 제공하는 방법을 써야 합니다.
그러나, 함수 객체( function object )는 increment 함수에 필요한 정보들을 다양한 방법으로 가질 수 있습니다.
class incrementObj{ // 함수 객체
int m_increment; // 상태 정보
public:
incrementObj(int incre) : m_increment(incre){}
int operator()(int n){ // () 연산자
return n + m_increment;
}
};
int main(){
int arr[] = {1, 2, 3, 4, 5};
int n = sizeof(arr)/sizeof(arr[0]);
int res[n];
int amount = 5; // 배열에 더하고 싶은 값
std::transform(arr, arr+n, res, incrementObj(amount)); // 함수 객체 사용
for (int x : res){
cout << x << " ";
}
return 0;
}
위와 같이, 함수 객체 incrementObj의 생성자를 통해서 필요한 정보를 제공하거나, 멤버 함수를 통해서 정보를 넣을 수도 있습니다.
참고로, std::transform 함수는 매개 변수를 두 개 갖는 함수를 사용하는 버전이 있습니다.
예를 들어, 두 배열의 값을 더한 결과를 다른 배열에 저장하는 기능이 필요할 때 이 버전을 사용합니다.
[C++] 입력된 원소들을 차례로 변환하는 std::transform
std::transform 기본 사용법std::transform은 지정된 함수 객체를 입력된 범위의 모든 원소들에게 적용하고, 그 결과를 대상 범위에 출력하는 함수입니다. 이 함수를 사용하려면 먼저 다음 헤더를
codingbonfire.tistory.com
템플릿( template )의 매개 변수로서의 함수 객체
C++ Standard Library는 다양한 함수 객체( function object )를 <functional> 헤더 파일을 통해서 제공하고 있습니다.
그리고, 이런 함수 객체들을 사용해서 표준 라이브러리 컨테이너의 목표를 달성하고 있습니다.
예를 들어, std::set의 선언은 다음과 같습니다.
template <class Key,
class Traits=less<Key>, // less는 함수 객체
class Allocator=allocator<Key>>
class set
이 중, 두 번째 매개 변수가 std::set 컨테이너의 원소를 정렬하는 데 사용되는 함수 객체입니다.
이 less 함수 객체의 선언은 다음과 같습니다.
template <class Type = void>
struct less : public binary_function <Type, Type, bool>
{
bool operator()(const Type& Left, const Type& Right) const;
};
이 함수 객체는 매개 변수 Left가 Right보다 작으면 true를 반환하고, 그렇지 않으면 false를 반환합니다.
이 반환 정보를 사용해서 std::set은 원소들을 정렬합니다.
물론, 다른 식으로 원소들을 정렬할 수도 있습니다.
예를 들어, 내림차순으로 정렬하고 싶다면, <functional> 파일이 제공하는 greater 함수 객체를 사용할 수 있습니다.
또는, 사용자 함수 객체를 작성해, 필요에 따른 정렬 방식을 제공할 수도 있습니다.
template<typename T> // 사용자 함수 객체
struct compObj{
bool operator()( const T& a, const T& b){
return a > b; // 내림차순으로 정렬
}
};
int main(){
std::set< int, compObj<int> > s; // 함수 객체를 인자로 전달
s.insert(3);
s.insert(5);
s.insert(7);
return 0;
}
위와 같이 함수 객체( 여기서는 compObj<int> 타입 )를 std::set의 원소를 정렬하는 객체의 타입으로 전달하는 대신, 함수를 사용할 수도 있는데, 약간 더 번거롭습니다.
이 때는, 아래와 같이 함수의 타입을 두 번째 인수로 넘기고, 사용될 구체적인 함수를 std::set의 생성자를 통해서 알려줘야 합니다.
template<typename T>
bool comp( const T& a, const T& b){ // 일반 비교 함수
return a > b;
}
template<typename T>
using CompType = bool(*)(const T&, const T&); // 비교 함수 타입
int main(){
set< int, CompType<int> > s(comp<int>); // 함수 객체와 함수 포인터 전달
s.insert(3);
s.insert(5);
s.insert(7);
}
C++ 11에 도입된 람다( lamda ) 함수를 사용하면 일반 함수를 사용하는 것보단 편리해집니다.
template<typename T>
auto lamda = [](const T&a, const T&b){ // 람다 함수
return a > b;
};
int main(){
set< int, decltype(lamda<int>) > s(lamda<int>);
s.insert(3);
s.insert(5);
s.insert(7);
}
람다 함수의 타입은 컴파일러만 알 수 있는 고유한 타입이기 때문에, decltype 키워드를 사용해서 람다의 타입을 알려주어야 합니다.
[C++] 간단한 함수 객체를 정의하기 위한 람다 표현식( lamda expression )
람다 표현식( lamda expression )줄여서 람다( lamda )라고도 하는 람다 표현식은 익명의 함수 객체를 정의하고 사용하기 위한 표기법입니다. 이 표현식은 간단한 기능을 구현하는데, 너무 많은 손이 가
codingbonfire.tistory.com
알고리즘에서 함수 객체 사용
std::sort 함수는 컨테이너나 배열의 원소를 원하는 방식으로 정렬하는 함수입니다.
이 함수는 정렬을 원하는 부분을 정하는 매개 변수와 두 원소를 비교하는 함수를 인자로 받는 함수입니다.
이때도, 두 원소를 비교하는 함수 대신 같은 역할을 하는 함수 객체( function object )를 사용할 수 있습니다.
다음 예제에서, 내림차순으로 정렬하는 함수 객체 greater를 볼 수 있습니다.
이 객체도 <functional> 헤더 파일에서 볼 수 있습니다.
#include <iostream>
#include <algorithm>
using namespace std;
int main(){
int arr[] = {1, 2, 3, 4, 5};
int n = sizeof(arr)/sizeof(arr[0]);
sort( arr, arr + n, greater<int>()); // 함수 객체를 전달
for( int x : arr){
cout << x << " ";
}
}
▼출력
5 4 3 2 1
이 때는, 함수 객체( 타입 )의 객체를 요구하기 때문에, greater<int>가 아니라, greater<int>()를 std::sort 함수에 인수로 알려줘야 합니다.
[C++] 배열, 컨테이터, 사용자 정의 데이터를 정렬하기 위한 std::sort
std::sort의 정의와 기초 사용법std::sort는 지정된 범위에 있는 데이터 요소를 기본적인 오름차순 또는 지정한 정렬 기준에 따라 정렬하는 함수입니다.이 함수를 사용하기 위해서는 우선 다음과 같
codingbonfire.tistory.com
'C++' 카테고리의 다른 글
| [C++] 모든 타입의 객체를 지시할 수 있는 void 포인터 (0) | 2025.03.18 |
|---|---|
| [C++] 간단한 함수 객체를 정의하기 위한 람다 표현식( lamda expression ) (0) | 2025.03.13 |
| [C++] 객체의 모든 원소를 순환하는 범위 기반 for 구문 (1) | 2025.03.11 |
| [C++] 단점을 보완한 범위 있는( scoped ) enum (0) | 2025.03.09 |
| [C++] 클래스의 멤버 함수를 가리키는 멤버 함수 포인터 (0) | 2025.03.06 |
