원본 : http://www.debuglab.com/knowledge/functionobject.html
1.요약
이 글을 통해서 배울 수 있는 것은
하나, accumulator 함수란 무엇인가
둘, function object 란 무엇인가
정도 되겠습니다.
이러한 것이 있구나라고 느끼시고, 다음에 비슷한 상황에 처하셨을 때 응용할 수 있는 내용입니다
.
2.본문
STL에는 accumulator 함수가 있습니다. 배열의 합, 리스트의 모든 원소의 곱.. 등등 커다란 자료구조를 순회하면서 특정연산을 하고 싶을 때 사용하시면 됩니다.
다음의 예를 보시면 한 번에 이해하실 수 있습니다.
- 다음의 예 -
이 예제에서 잠시 언급해야 할 부분은
accumulate 함수는 numeric 헤더파일에 있다는 것과 ( 물론 VC++의 경우입니다.)
그리고 기존의 using namespace std 대신에 using std::accumulate 를 사용했다는 것입니다.
두 개의 차이점은 전자가 std namespace안의 모든 심볼을 디폴트로 사용하겠다는 의미인 반면에 후자는 std namespace 안의 accumulate라는 심볼만 디폴트로 사용하겠다는 의미가 되겠죠.
여기서 디폴트란 std::accumulate 안하고 accumulate라고만 해도 std namespace의 accumulate인지 알아듣는다는 의미입니다.
---------------------------------------------------------
그럼 이쯤에서 accumulate의 구현을 공개하겠습니다.
_V는 반환할 값의 맨 처음 초기값을 의미하며 그 타입인 _Ty는 int와 대응되겠죠 _B는 특정 연산을 수행할 함수의 주소를 나타내며 그 타입인 _Bop는 위의 예에서 int (*)(int, int) 와 대응되겠죠. 쉽게 풀어서 말하면
< int를 반환하고 int형 인자 2개를 받는 함수의 포인터형 >
전체적으로 정리를 해서 위의 예와같이 accumulate를 사용했다면 컴파일러는 다음과 같은 원형의 accumulate함수를 내부적으로 만들었을 겁니다.
일단 다음의 예를 또 보시죠
- 예제 2 -
이 어찌 된 일이며, 이것이 컴파일 되는 이유는 무엇일까요?
-----------------------------------------------------------
CAdd는 () operator를 오버로딩 했습니다. 그러므로 다음과 같은 사용이 가능합니다.
예제 2에서 처럼 accumulate 함수를 호출한다면 컴파일러는 어떠한 원형의 accumulate 함수를 만들까요?
다음과 같겠죠..
이제 글이 끝났습니다.
이런 용도로 만든 클래스를 function object라고 부를 수 있습니다.
함수를 전달하는 것보다 function object를 전달하는 것이 좋은 이유는 무엇일까요?
1. 함수와는 달리 부가적인 정보를 함께 전달할 수 있습니다.
2. 멤버 함수가 inline으로 선언되므로 보다 효율적이 될 수 있습니다.
2번의 경우에는 조금 토를 달아야겠네요. 일반 함수도 inline으로 선언할 수 있는 건 사실이지만 어디선가 그 함수의 주소를 요구한다면 inline으로 만들어 질 수 없습니다. 그렇기 때문에 수행속도에 영향을 받을 것이 확실합니다.그렇게 생각하면 2번은 맞는 말입니다.
테스트 결과도 그렇게 나옵니다.
하지만 주소를 요구하는 accumulate 함수 역시 inline으로 선언된 경우라면 함께 inline으로 만들어질 수 있습니다.
테스트 결과 function object를 사용한 경우와 같은 성능을 보여주었습니다.
3.예제
4.참고
STL Tutorial and Reference Guide
(C++ Programming with the Standard Template Library)
- Addison-Wesley
- 2001.08.19 Smile Seo -
1.요약
이 글을 통해서 배울 수 있는 것은
하나, accumulator 함수란 무엇인가
둘, function object 란 무엇인가
정도 되겠습니다.
이러한 것이 있구나라고 느끼시고, 다음에 비슷한 상황에 처하셨을 때 응용할 수 있는 내용입니다
.
2.본문
STL에는 accumulator 함수가 있습니다. 배열의 합, 리스트의 모든 원소의 곱.. 등등 커다란 자료구조를 순회하면서 특정연산을 하고 싶을 때 사용하시면 됩니다.
다음의 예를 보시면 한 번에 이해하실 수 있습니다.
- 다음의 예 -
// 1에서 10까지 합을 구하는 프로그램
#include <numeric>
#include <assert.h>
using std::accumulate;
int ADD(int x, int y) {return x + y;}
void main(int argc, char* argv[])
{
int i[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int product = accumulate( &i[0], &i[10], 0, ADD);
assert( 55 == product);
}
다음의 예에서 보셨듯이 자료구조의 처음과 끝을 알리고는 계산에 쓸 함수를 대입해주면 됩니다. 이 예제에서 잠시 언급해야 할 부분은
accumulate 함수는 numeric 헤더파일에 있다는 것과 ( 물론 VC++의 경우입니다.)
그리고 기존의 using namespace std 대신에 using std::accumulate 를 사용했다는 것입니다.
두 개의 차이점은 전자가 std namespace안의 모든 심볼을 디폴트로 사용하겠다는 의미인 반면에 후자는 std namespace 안의 accumulate라는 심볼만 디폴트로 사용하겠다는 의미가 되겠죠.
여기서 디폴트란 std::accumulate 안하고 accumulate라고만 해도 std namespace의 accumulate인지 알아듣는다는 의미입니다.
---------------------------------------------------------
그럼 이쯤에서 accumulate의 구현을 공개하겠습니다.
template<class _II, class _Ty, class _Bop> inline
_Ty accumulate(_II _F, _II _L, _Ty _V, _Bop _B)
{
for (; _F != _L; ++_F)
_V = _B(_V, *_F);
return (_V);
}
변수 이름이 징그럽게 생겨서 보기 힘들기는 하지만 별 것 없습니다. 인자부분을 보시면 _F, _L은 처음과 끝 원소의 위치를 나타내죠.. 타입인 _II는 위의 예에서 int*에 대응되겠죠. _V는 반환할 값의 맨 처음 초기값을 의미하며 그 타입인 _Ty는 int와 대응되겠죠 _B는 특정 연산을 수행할 함수의 주소를 나타내며 그 타입인 _Bop는 위의 예에서 int (*)(int, int) 와 대응되겠죠. 쉽게 풀어서 말하면
< int를 반환하고 int형 인자 2개를 받는 함수의 포인터형 >
전체적으로 정리를 해서 위의 예와같이 accumulate를 사용했다면 컴파일러는 다음과 같은 원형의 accumulate함수를 내부적으로 만들었을 겁니다.
inline
int accumulate(
int* _F,
int* _L,
int _V,
int (*_B)(int, int));
자 여기까지 이해를 하셨으면 이제 본론에 들어갈 차례입니다. 일단 다음의 예를 또 보시죠
- 예제 2 -
#include <numeric>
#include <assert.h>
using std::accumulate;
class CAdd
{
public:
int operator()(int x, int y) const { return x + y;}
};
void main(int argc, char* argv[])
{
int i[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int product = accumulate( &i[0], &i[10], 0, CAdd());
assert( 55 == product);
}
차이점은 ADD함수가 사라지고 클래스 CAdd가 나타났으며 당연 함수의 주소를 넘겨야할 곳에 CAdd() 를 넘겨주었습니다. 이 어찌 된 일이며, 이것이 컴파일 되는 이유는 무엇일까요?
-----------------------------------------------------------
CAdd는 () operator를 오버로딩 했습니다. 그러므로 다음과 같은 사용이 가능합니다.
CAdd a; int Iam_8 = a( 3, 5);이제 시나리오를 다시 생각해봅시다.
예제 2에서 처럼 accumulate 함수를 호출한다면 컴파일러는 어떠한 원형의 accumulate 함수를 만들까요?
다음과 같겠죠..
inline
int accumulate(
int* _F,
int* _L,
int _V,
CAdd _B));
그리고 _B는 함수의 포인터처럼 _B(_V, *_F)이렇게 사용될 것이고 문법적으로 아무런 문제가 없습니다. 그렇죠? 이제 글이 끝났습니다.
이런 용도로 만든 클래스를 function object라고 부를 수 있습니다.
함수를 전달하는 것보다 function object를 전달하는 것이 좋은 이유는 무엇일까요?
1. 함수와는 달리 부가적인 정보를 함께 전달할 수 있습니다.
2. 멤버 함수가 inline으로 선언되므로 보다 효율적이 될 수 있습니다.
2번의 경우에는 조금 토를 달아야겠네요. 일반 함수도 inline으로 선언할 수 있는 건 사실이지만 어디선가 그 함수의 주소를 요구한다면 inline으로 만들어 질 수 없습니다. 그렇기 때문에 수행속도에 영향을 받을 것이 확실합니다.그렇게 생각하면 2번은 맞는 말입니다.
테스트 결과도 그렇게 나옵니다.
하지만 주소를 요구하는 accumulate 함수 역시 inline으로 선언된 경우라면 함께 inline으로 만들어질 수 있습니다.
테스트 결과 function object를 사용한 경우와 같은 성능을 보여주었습니다.
3.예제
4.참고
STL Tutorial and Reference Guide
(C++ Programming with the Standard Template Library)
- Addison-Wesley
- 2001.08.19 Smile Seo -
"STL" 카테고리의 다른 글
- A beginner's tutorial on STL (0)2007/07/17
- 표준 템플릿 라이브러리(STL, Standard Template L... (0)2007/05/17
- 함수대신 function object를 대입하자 (0)2007/03/23
- 정렬과 탐색 루틴이 필요하신 분 (0)2007/03/23

수안이의 컴퓨터 연구실



Leave your greetings.