이 글은 https://www.bogotobogo.com/cplusplus/functors.php을 해석한 것입니다.
Functor(함수 객체 또는 functional)은 객체+() 이런 구조로 이루어져 있습니다.
functor는 함수처럼 실행시키기 위해 operator()을 쓸 수 있는 다양한 객체들을 말합니다. 여기에는 일반 함수(normal functions), 포인터 함수(pointers to functions), 그리고 클래스 객체들이 포함됩니다. 즉 functor의 기본 조건에는 operator()가 오버로딩되있어야 한다는 뜻입니다.
우리는 평소에 쓰던 소위 흔한 함수들이 동작하지 않을 때 함수 객체를 쓸 수 있습니다. STL은 꽤나 자주 함수 객체들을 사용하고, 요긴하게 쓸 수 있는 몇 가지의 함수 객체들을 제공해주기도 합니다.
함수 객체는 제네릭 프로그래밍의 힘과 순수 추상화(순수 가상 함수 등)의 개념을 보여줍니다. 많은 개발자들이 함수처럼 동작하는 모든 것은 함수라고 명명합니다. 그렇기 때문에, 우리가 어떤 객체를 함수처럼 사용할 수 있도록 정의해준다면, 그건 함수라고 부를 수 있게 되는 것이죠.
예를 들어 아래와 같이 absValue라는 이름의 구조체를 하나 만들어 보겠습니다. 이 친구는 float타입의 값을 절댓값으로 바꿔주는 연산을 가지고 있습니다.
#include <iostream>
struct absValue
{
float operator()(float f) {
return f > 0 ? f : -f;
}
};
int main( )
{
using namespace std;
float f = -123.45;
absValue aObj;
float abs_f = aObj(f);
cout << "f = " << f << " abs_f = " << abs_f << endl;
return 0;
}
결과값은 다음과 같습니다:
f = -123.45 abs_f = 123.45
코드에 정의해둔 것과 같이, aObj는 함수가 아니라 객체인데도 우리는 이 객체를 호출할 수 있습니다. 호출을 하게 되면 absValue에 오버로딩 되어 있는 호출 연산자가 실행됩니다. 이 연산자는 float 값을 절댓값으로 바꾸어 반환합니다. 그러므로 함수 호출 연산자는 무조건 멤버 함수로 정의되어 있어야 한다는 걸 꼭 기억해야 합니다.
즉, absValue 객체처럼 호출 연산자가 정의되어 있는 클래스 타입의 객체들은 함수 객체처럼 참조되게 됩니다.
다른 예시를 한 번 들어보겠습니다. 이 클래스 객체는 x를 받아 다음과 같은 y 좌표를 돌려주는 functor처럼 작동합니다.
y = ax + b
코드는 다음과 같습니다:
#include <iostream>
using namespace std;
class Line {
double a; // slope
double b; // y-intercept
public:
Line(double slope = 1, double yintercept = 1) : a(slope), b(yintercept) {}
double operator()(double x) {
return (a*x + b);
}
};
int main () {
Line fa; // y = 1x + 1
Line fb(5.0, 10.0); // y = 5x + 10
double y1 = fa(20.0); // y1 = 20 + 1
double y2 = fb(3.0); // y2 = 5*3 + 10
cout << "y1 = " << y1 << "y2 = " << y2 << endl;
return 0;
}
조건자 (Predicates)
STL은 functor의 개념을 다음과 같이 다듬었습니다:
1. generator는 인자 없이 호출할 수 있는 functor이다.
2. unary function은 하나의 인자로 호출할 수 있는 functor이다.
3. binary function은 두 개의 인자로 호출할 수 있는 functor이다.
이전 섹션에서 보았던 for_each()를 사용하기 위한 print_it functor는 컨테이너 요소를 하나 받고 있으므로 unary function입니다.
알고리즘의 특별한 보조 함수가 바로 조건자(predicate)입니다. 조건자는 boolean 값(또는 암시적으로 bool로 변환되는 어떤 값)을 리턴하는 함수입니다. 즉 predicate class는 operator() 함수가 조건자인 functor 클래스입니다. 이 operator() 가 불값인 true 또는 false를 반환하기 때문이죠.
조건자는 STL 내에서 굉장히 많이 쓰이고 있습니다. 대표적으로 map, set과 같은 표준 연관 컨테이너의 비교 함수들이 있습니다.
조건자 함수들은 보통 알고리즘에게 파라미터로써 전달됩니다. find_if 처럼요.
목적에 따라, 조건자는 unary와 binary로 나뉩니다.
1. bool 값을 반환하는 unary function는 조건자이다.
2. bool값을 반환하는 binary function은 binary 조건자이다.
선정의된 함수 객체(Predefined Functions Objects)
STL에서 선정의된 함수 객체의 대표적인 예가 set입니다. set은 요소들을 오름차순으로 정렬합니다. 디폴트로 less(<) 정렬 기준을 가지기 때문입니다.
우리가 다음과 같이 선언을 해주면
set<int> mySet;
내부 코드는 다음과 같습니다:
set<int, less<int> > mySet;
만약 set에 저장되는 요소들을 내림차순으로 정렬하고 싶어지면 다음과 같이 less 대신 greater를 쓰도록 명시하시면 됩니다.
set<int, greater<int> > mySet;
'C++' 카테고리의 다른 글
move semantic과 lvalue, rvalue (2) | 2024.10.24 |
---|---|
std::vector 란? (0) | 2024.10.23 |
해쉬 테이블 (1) | 2024.02.11 |