STL 함수 객체

seio·2022년 10월 9일
0

C++ STL

목록 보기
12/17

함수 객체(function object)는 함수자(functor)라는 애칭으로 더 많이 사용되며, operator() 연산자를 오버로딩한 클래스 객체이다.

STL의 함수 객체는 다음 두 가지로 분류할 수 있다.

  • 1)일반 함수 객체: 특정 기능을 수행하는 함수 객체

    • 산순 연산 함수 객체: 산술 연산 기능을 수행 (plus, minus, multiplies, divides, mudulus, negate)
    • 비교 연산 함수 객체 조건자: 비교 조건자(equal_to, not_equal_to, less, greater, greater_equal, less_equal)
    • 논리 연산 함수 객체 조건자: 논리 조건자(logical_and, logical_or, logical_not)
  • 2) 함수 어댑터(function adaptor): 함수류(함수 객체, 함수, 함수 포인터)를 인자로 받아 다른 함수 객체로 변환

    • 바인더(binder): 이항 함수 객체를 단항 함수 객체로 변환 (bind1st, bind2nd)
    • 부정자(negator): 함수 객체 조건자를 반대로 변환(not1, not2)
    • 함수 포인터 어댑터: 함수 포인터를 STL이 요구하는 함수 객체로 변환(ptr_fun)
    • 멤버 함수 포인터 어댑터: 멤버 함수 포인터를 STL이 요구하는 함수 객체로 변환 (mem_fun, mem_fun_ref)

여기서 조건자는 bool 형식을 반환하는 함수류(함수 객체, 함수, 함수 포인터)이다. 많은 알고리즘에 이런 함수류를 사용자 조건으로 지정하여 알고리즘이 유연하게 동작하도록 한다.

struct LessFunctor // 1. 함수 객체
{
	bool operator()(int left, int right) const
	{
		return left < right;
	}
};

bool LessFun(int left, int right){ // 2. 함수 조건자
	return left < right;
}

int main(){
	bool (*LessPtr)(int,int) = LessFun; // 3. 함수 포인터 조건자
	LessFunctor lessFunctor;
    
    //bool 형식을 반환
    //1. 함수 객체로 10과 20을 비교
    cout<<lessFunctor(10, 20)<<endl;
    
    //2. 함수로 10과 20을 비교
    cout<<LessFun(10, 20)<<endl;
        
    //3. 함수 포인터로 10과 20을 비교
    cout<<LessPtr(10, 20)<<endl;
	
    return 0;
}

[출력 결과]
1
1
1

이런 조건자 중 STL에서 제공하는 조건자는 모두 함수 객체 조건자이다. bool형식을 반환하는 함수 객체라고 해서 모두 함수 객체 조건자(function object predicate)는 아니며 조건자는 객체의 상태값을 변경할 수 없다는 '요구조건'을 만족해야 한다. 그래서 함수 객체 조건자의 operator() 연산자 오버로딩 함수는 모두 const 함수이다.

이유는 조건자를 사용하는 많은 알고리즘에서 조건자가 변경되지 않는다는 전제 하에 조건자를 내부적으로 복사하며, 이때 조건자의 상태값이 변경되며 예기치 못한 동작이 발생하기 때문이다. 그래서 STL 조건자는 '내부 상태가 변경되지 않는 bool 형식을 반환하는 함수 객체'이다.

또한 어댑터의 인자로 사용되는 함수 객체는 모두 다음 요구 사항을 지켜야한다.

  • 단항 함수 객체는 반드시 argument_type, result_type이 정의돼 있어야 한다. 각각은 함수의 인자 형식과 리턴 형식이다.
  • 이항 함수 객체는 반드시 first_argument_type, second_argument_type, result_type이 정의돼 있어야 한다. 각각은 함수의 첫 번째 인자 형식과 두 번째 인자 형식, 리턴 형식이다.

어댑터(adaptor)는 함수 객체를 다른 함수 객체로 변환할 때 위 정의 형식을 이용해 변환을 수행합니다. 이러한 형식 정의를 쉽게 하려고 STL은 기본 클래스 unary_function과 binary_function을 제공한다. 따라서 위 형식들을 직접 정의할 필요가 없으며, 함수 객체는 위 기본 클래스를 상속받아 만들면 된다.

예제


templat<typename T>
struct Plus{
	T operator()(const T& left, const T& right)const{
    	retunr left+ right;
    }
};

void main{
	vector<int> v1;// 10, 20, 30
    vector<int> v2;// 1, 2, 3
    vector<int> v3(3);
	
    //STL 조건자 plus<int> 사용
    //transfor, (v1.begin(), v1.end(), v2.begin(),v3.begin(),plus<int>());
    
    //사용자 정의 조건자 Plus<int> 사용
    transform(v1.begin(),v1.end(),v2.begin(),v3.begin(), Plus<int>());
 
 // cout<<v1<<v2<<v3<<endl
 
}
[출력 결과]
v1: 10, 20, 30
v2: 1, 2, 3
v3: 11, 22, 33

vector v1에 모든 원소에 100을 더하고자 한다. 사용자가 정의한 함수 객체 Plus를 이용하려면 이항 함수 객체인 Plus의 한 인자를 100으로 고정하고, 또한 다른 인자는 v1의 원소를 인자로 받게 한다. 한마디로 이항 함수 객체 Plus를 단항 함수 객체(한 항을 고정(100))로 변환하면 된다. 이때 어댑터 binder1st를 사용할 수 있다.

struct Plus{...};
void main{
	...
	transfrom(v1.begin(),v1.end(),v3.begin(),binder1st<Plus<int>>(Plus<int>,100));
}

transform() 알고리즘은 단항 함수자 버전을 사용했다. 중요한 것은 ** STL plus 함수자는 잘 실행되지만 사용자 Plus는 엄청난 에러가 발생한다. 이유는 어댑터 binder1st가 이항 함수자를 단항 함수자로 변환하기 위해 first_argument_type, second_argument_type,result_type 형식 정의를 필요로 하기 때문이다.

// 사용자 함수 객체도 어댑터 적용이 가능하도록 필요 형식을 정의한 예제

	template<typename T>
    struct Plus{
    	typedef T first_argument_type;
        typedef T second_argument_type;
        typedef T result_type;
        
        T operator()(const T& left ,const T& right) const
        {
        	return left+right;
        }
    };
    
    void main(){
     ...
     transfrom(v1.begin(),v1.end(),v3.begin(),binder1st<Plus<int>>(Plus<int>,100));
    }

STL 함수자 plus나 사용자 함수자 Plus 모두 binder1st를 사용할 수 있으며 잘 실행된다.

이렇게 직접 함수자에 first_argument_type, second_argument_type, result_type 형식을 정의할 수 있지만, 기본 클래스 unary_function과 binary_function을 상속받아 구현하는 것이 더 일반적이고 쉽다.

// 이항 함수자 객체가 어댑터 변환이 가능하게 기본 클래스 binary_function을 상속한 예제

	template<typename T>
    struct Plus: public binary_function<T,T,T>
    {
    	T operator()(const T& left, const T& right)const{
        	return left+right;
        }
    };
    
    int main(){
    transfrom(v1.begin(),v1.end(),v3.begin(),binder1st<Plus<int>>(Plus<int>,100));
    }

사용자 함수 객체(함수자)를 구현할 때 단항 함수자는 기본 클래스 unary_function을 상속받아 만들고 이항 함수자는 binary_function을 상속받아 만들면 된다.

산술 연산 함수 객체

링크: 링크텍스트

비교 연산 조건자

링크: 링크텍스트

논리 연산 조건자

링크:링크텍스트

바인더 & 부정자

링크:링크텍스트

함수 포인터 어댑터

링크: 링크텍스트

profile
personal study area

0개의 댓글