함수자 클래스는 어댑터 적용이 가능하게(adaptable) 만들자.

list<Widget*> widgetPts;
bool isInteresting(const Widget* pw);
위와 같은 컨테이너와 함수가 있을때 find 알고리즘을 이용해서 isInteresting가 true를 반환하는 Widget 포인터 객체를 찾을수 있다.
list<Widget*>::iterator i = find_if( widgetPtrs.begin(),
widgetPtrs.end(),
isInteresting);
if( i != widgetPtrs.end() )
{
….
}
만약 not1 어댑터를 적용하여 isInteresting가 false를 반환하는 첫번째 포인터 값을 얻기 위해서는
list<Widget*>::iterator i = find_if( widgetPtrs.begin(),
widgetPtrs.end(),
not1(isInteresting));
으로 적용할수가 없다. isInteresting는 not1 이 필요로하는 typedef 문을 제공하지 않기 때문이다. 위의 코드는
list<Widget*>::iterator i = find_if( widgetPtrs.begin(),
widgetPtrs.end(),
not1(ptr_fun(isInteresting)));
으로 수정하여 정상적으로 수행이 가능하다. 즉 ptr_fun은 어댑터의 적용이 가능하도록 typedef를 정의해주는 역할을 하는 것이다.
STL의 4대 표준 함수 어댑터(not1, not2, bind1st, bind2nd)는 모두 특정 typedef가 있어야 하고 STL과 호환하는 비표준 어댑터 역시 마찬가지이다. 어댑터에서 요구하는 typedef를 제공하는 함수객체를 어댑터 적용이 가능하다 라고 표현하며 ptr_fun 은 일반 함수 포인터를 어댑터 적용이 가능한 상태로 바꾸어 주는 역할을 하는 것이다.

일단 어뎁터를 직접만드는 내용은 패스.
어쨋거나 이런 어뎁터를 적용가능한 함수객체를 만드는 방법은 직접 typedef를 써서 만들면 피곤하므로 특정 탬플릿을 상속받아 만들면 된다. 바로 std::unary_functionstd::binary_function 이다.
template<typename T>
class MeetsThreshold : public std::unary_function<Widget, bool>{
private:
const T threshold;
public:
MeetsThreshold(const T& threshold);
bool operator()(const Widget&) const;
….
};

struct WigetNameCompare : std::binary_function<Widget,Widget,bool>
{
bool operator()(const Widget& lhs, const Widget& rhs) const;
};

위의 코드에서 볼수 있듯이 상속하는 unary_function, binary_function 의 탬플릿 매개변수가 상속받는 함수객체의 operator() 함수의 매개변수와 리턴하는 변수형이다.
WigetNameCompare가 구조체인 이유는 일반적으로 내부 상태 데이터가 없는 함수객체의 경우 구조체로 선언하는 것이다.
그리고





binary_function<Widget,Widget,bool>
bool operator()(const Widget& lhs, const Widget& rhs) const;

에서 보는것 처럼 unary_function, binary_function 는 operator()가 받는 매개변수의 타입이 비포인터 타입인 경우 const 와 참조자 표시는 빼는것이 상례이다.
ex) const Widget& -> Widget

그런데 operator()가 포인터를 매개 변수로 받는 경우에는 unary_function, binary_function 의 템플릿 매개변수와 operator()의 매개변수 타입이 동일하다.
struct PtrWidgetNameCompare:
std::binary_function<const Widget*, const Widget* bool>{
bool operator()(const Widget* lhs, const Widget* rhs) const;
};

어쨋거나 결론은 함수객체를 만들때는 위와 같은 클래스를 상속받아 어뎁터적용이 가능한 객체를 만드는것이 요긴하다 라는 것이다.

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다