CS/C++

뇌를 자극하는 C++ STL : 9장. 함수 객체

샤아이인 2022. 1. 18.

내돈내고 내가 공부한것을 올리며, 중요한 단원은 저 자신도 곱씹어 볼겸 가겹게 포스팅 하겠습니다.

1) 9장. 함수 객체

STL에서는 다양한 함수 객체를 제공한다고 한다. STL의 함수 객체는 클라이언트 코드 에서 만든 함수를 callback형식으로 다른 구성 요소에 반영하기 위해 사용된다. 많은 알고리즘이 STL함수 객체를 알고리즘의 인자로 받아 작동한다.

함수 객체는 <functional> 헤더에 정의되어 있다.

 

나같은경우 함수 객체보다는 Functor라는 단어가 입에 붙었기에 Functor라는 말을 주로 사용하겠다.

 

STL의 함수 객체의 분류

▶ 일반 함수 객체: 특정 기능을 수행하는 함수 객체

- 산술 연산 함수 객체

- 비교 연산 함수 객체 조건자

- 논리 연산 함수 객체 조건자

 

 함수 어댑터: 함수류를 인자로 받아 다른 함수 객체로 변환

- 바인더

- 부정자

- 함수 포인터 어댑터

- 멤버 함수 포인터 어댑터

 

함수 객체, 함수, 함수 포인터 조건자에 대하여 코드로 알아보자.

#include <iostream>
using namespace std;

struct LessFunctor { // Functor 조건자
	bool operator() (const int& left, const int& right) const
	{
		return left < right;
	}
};

bool LessFun(const int& left, const int& right) // function 조건자
{
	return left < right;
}

int main()
{
	bool (*LessPtr)(const int&, const int&) = LessFun; // function pointer 조건자
	LessFunctor lefunctor;

	cout << boolalpha;
	// Functor로 비교
	cout << lefunctor(7, 9) << endl;

	// function으로 비교
	cout << LessFun(7, 9) << endl;

	// function pointer로 비교
	cout << LessPtr(10, 20) << endl;

	return 0;
}
 

결과로는 다음과 같다.

이런 조건자 중 STL에서 제공하는 조건자는 모두 함수 객체 조건자(Functor)이다. 조건자는 객체의 상태값을 변경할 수 없다는 '조건' 을 만족해야만 한다.

따라서 const를 적극 사용한다. STL 조건자는 '내부 상태가 변경되지 않는 bool형식을 반환하는 함수 객체' 이다.

 

어댑터는 함수 객체를 다른 함수 객체로 변환하기 위해 단한함수 객체조건 or 이항 함수 객체조건을 만족하는 정의 형식을 통해 변환을 수행한다. 따라서 변환할 함수 객체를 unary_function과 binary_function을 상속받아 사용하면 된다.

 

다음 코드는 이항 함수자 객체가 어댑터 변환이 가능하도록 binary_function을 사용한 코드이다.

#include <iostream>
#include <algorithm>
#include <vector>
#include <functional>
using namespace std;

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()
{
	vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);

	vector<int> v2(3);
	transform(v1.begin(), v1.end(), v2.begin(), binder1st<plus<int>>(plus<int>(), 10));

	cout << "v2 : ";
	for (vector<int>::size_type i = 0; i < v2.size(); i++)
		cout << v2[i] << " ";
	cout << endl;

	return 0;
}
 

결과로는 다음과 같다.

두번째 인자 10 정상적으로 값이 더해진것을 확인할수 있었다.

 

이번 예제는 큰 문제가 하나 있다. 이러한 binder1st와 binary_function을 사용하는 방식은 C++17에서 사라진 내용이다.

나같은 경우 원래 C++17 컴파일러로 두고 코딩을 하는데 처음에 책에 있는대로 코드를 짜도 binder1st를 인식하지 못하길레 구글링 해본결과 사라진 문법이였다. 위의 결과는 컴파일러 옵션을 C++14로 변경후 실행한 것 이다.

 

 

binder1st 클래스

자세한 정보: binder1st 클래스

docs.microsoft.com

 

 

그럼 C++17이상에서는 이러한 방식을 어떻게 해결할가?? 이는 추후 C++17을 공부할때 알아보는것으로 잠시 미루어 둬야겠다.

 

산술 연산 함수 객체

#include <iostream>
#include <functional>
using namespace std;

int main()
{
	cout << "5 + 10 = " << plus<int>()(5, 10) << endl;
	cout << "5 - 10 = " << minus<int>()(5, 10) << endl;
	cout << "5 * 10 = " << multiplies<int>()(5, 10) << endl;
	cout << "5 / 10 = " << divides<int>()(5, 10) << endl;
	cout << "5 % 10 = " << modulus<int>()(5, 10) << endl;
	cout << "- 5 = " << negate<int>()(5) << endl;
	return 0;
}
 

결과는 생각한대로 나온다.

 

비교 연산 조건자

#include <iostream>
#include <functional>
using namespace std;

int main()
{
	cout << "5 == 10 " << equal_to<int>()(5, 10) << endl;
	cout << "5 != 10 " << not_equal_to<int>()(5, 10) << endl;
	cout << "5 < 10 " << less<int>()(5, 10) << endl;
	cout << "5 <= 10 " << less_equal<int>()(5, 10) << endl;
	cout << "5 > 10 " << greater<int>()(5, 10) << endl;
	cout << "5 >= 10 " << greater_equal<int>()(5, 10) << endl;
	return 0;
}
 

함수 포인터 어댑터

함수 포인터 어댑터는 일반적으로 사용자가 만든 함수를 어댑터 적용이 가능하도록 함수 객체로 변환하는 함수이다.

STL에서는 ptr_fun()이라는 함수 포인터 어댑터를 제공한다. 이를 통해 argumnet_type과 result_type이 정의된 함수 객체로 변환시킨다.


 

2) 나의 현황

하 자료구조 무슨 책으로 공부해야한느것 일까... C++로 공부하고 싶은데 바이블 이라 불리는 C++ 자료구조론 이라는 책이 집에 있기는 한데 뭐랄까 너무 이론위주 책 아닌가? 싶기도 하고.. 머리가 복잡하다.

이글의 모든 사진과 내용의 출처는 공동환 님께 있습니다.

댓글