오늘은 술어 구문(predicate)와 어댑터(not1(), not2(), bind1st(), bind2st())를 공부하겠습니다.
이 페이지를 공부하려면 기초적인 STL을 알아야 합니다.
1, 술어 구문(predicate)
술어 구문(predicate)이란 bool형을 반환하는 함수류입니다. 즉, 비교 함수입니다.
함수 역할을 하는 함수자(functor)도 operator()가 bool형을 반환하면 술어 구문이겠죠?
대표적인 술어 구문 클래스가 less와 greater 클래스입니다.
less와 greater 클래스는 사용자 정의가 가능한 술어 구문 함수자 클래스입니다.
술어 구문 함수 예제입니다.
#include <iostream>
#include <functional>
using namespace std;
bool LessPredicate(int left, int right)
{
return left < right;
}
void main( )
{
cout << LessPredicate(10, 20) << endl;
cout << LessPredicate(10, 10) << endl;
cout << LessPredicate(20, 10) << endl;
}
- 1
0
0
LessPredicate()함수는 bool을 반환하므로 술어 구문(predicate)입니다. 쉽죠~~잉!
less와 greater를 공부해 볼까요?
#include <iostream>
#include <functional>
using namespace std;
void main( )
{
less<int> lessPred; // 함수 < 와 같은 기능
cout << lessPred( 10, 20 ) << endl;
cout << lessPred( 10, 10 ) << endl;
cout << lessPred( 20, 10 ) << endl<<endl;
greater<int> greaterPred; // 함수 > 와 같은 기능
cout << greaterPred( 10, 20 ) << endl;
cout << greaterPred( 10, 10 ) << endl;
cout << greaterPred( 20, 10 ) << endl<<endl;
less_equal<int> less_ePred; // 함수 <= 와 같은 기능
cout << less_ePred( 10, 20 ) << endl;
cout << less_ePred( 10, 10 ) << endl;
cout << less_ePred( 20, 10 ) << endl<<endl;
greater_equal<int> greater_ePred; // 함수 >= 와 같은 기능
cout << greater_ePred( 10, 20 ) << endl;
cout << greater_ePred( 10, 10 ) << endl;
cout << greater_ePred( 20, 10 ) << endl<<endl;
}
- 1
0
0 -
- 0
0
1 -
- 1
1
0 -
- 0
1
1
bool operator( T , T ) 멤버 함수를 갖는 함수자 클래스입니다.
보통 임시객체를 만들어 사용합니다.
#include <iostream>
#include <functional>
using namespace std;
void main( )
{
cout << less<int>()( 10, 20 ) << endl;
cout << greater<int>()( 20, 10 ) << endl;
}
- 1
1
객체 단독으로 사용되는 경우가 없으므로 이 예제처럼 임시 객체를 만들어 바로 사용합니다.
less와 greater의 실제 사용 예를 보겠습니다.
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;
void Print(const vector<int>& v)
{
vector<int>::const_iterator iter;
for(iter = v.begin() ; iter != v.end() ; iter++)
cout << *iter <<' ';
cout << endl;
}
void main()
{
vector<int> v(10);
int i;
for(i = 0 ; i < (int)v.size() ; i++ )
v[i] = rand() % 1000;
Print( v );
sort(v.begin(), v.end(), less<int>()); // less<int>() 생략가능
Print( v );
sort(v.begin(), v.end(), greater<int>());
Print( v );
}
- 41 467 334 500 169 724 478 358 962 464
41 169 334 358 464 467 478 500 724 962
962 724 500 478 467 464 358 334 169 41
첫 번째 결과는 정렬 전입니다.
두 번째 결과는 less predicate를 사용한 정렬입니다.
세 번째 결과는 greater predicate를 사용한 정렬입니다.
연관 컨테이너 set, map은 디폴트로 less를 사용하여 내부 트리를 유지합니다.
간단한 예제를 보겠습니다.
#include <iostream>
#include <map>
#include <algorithm>
#include <functional>
using namespace std;
void main( )
{
map<int, double > lessMap; // less<int> 생략
map<int, double, greater<int> > greaterMap;
lessMap.insert(pair<int,double>(10,1.5) );
lessMap.insert(pair<int,double>(40,4.5) );
lessMap.insert(pair<int,double>(50,5.5) );
lessMap.insert(pair<int,double>(30,3.5) );
lessMap.insert(pair<int,double>(20,2.5) );
greaterMap.insert(pair<int,double>(10,1.5) );
greaterMap.insert(pair<int,double>(40,4.5) );
greaterMap.insert(pair<int,double>(50,5.5) );
greaterMap.insert(pair<int,double>(30,3.5) );
greaterMap.insert(pair<int,double>(20,2.5) );
map<int , double, less<int> >::iterator iter;
for(iter = lessMap.begin() ; iter != lessMap.end() ; iter++)
cout << iter->first << ',' << iter->second << endl;
cout << "==============" << endl;
map<int , double, greater<int> >::iterator giter;
for(giter = greaterMap.begin() ; giter != greaterMap.end() ; giter++)
cout << giter->first << ',' << giter->second << endl;
}
- 10,1.5
20,2.5
30,3.5
40,4.5
50,5.5
==============
50,5.5
40,4.5
30,3.5
20,2.5
10,1.5
map에 less와 greater를 사용했을 때 내부적으로 정렬된 출력결과를 보여줍니다. inorder 출력 결과를 볼 수 있습니다.
less는 오름차순으로 왼쪽에 작은 값을 오른쪽에 큰 값을 위치시키고 greater는 반대입니다.
이제 less와 greater를 직접 만들어 볼까요?
#include <iostream>
#include <map>
#include <algorithm>
#include <functional>
using namespace std;
template <typename T>
struct Less
{
bool operator ( ) (const T& left, const T& right)
{
return left < right;
}
};
template <typename T>
struct Greater
{
bool operator ( ) (const T& left, const T& right)
{
return left > right;
}
};
void main( )
{
Less<int> lessPred; // 함수 < 와 같은 기능
cout << lessPred( 10, 20 ) << endl;
cout << lessPred( 10, 10 ) << endl;
cout << lessPred( 20, 10 ) << endl<<endl;
Greater<int> greaterPred; // 함수 > 와 같은 기능
cout << greaterPred( 10, 20 ) << endl;
cout << greaterPred( 10, 10 ) << endl;
cout << greaterPred( 20, 10 ) << endl<<endl;
}
- 1
0
0 -
- 0
0
1
직접 만들어 사용한 예제입니다. 결과는 less, greater와 동일합니다.
2, 어댑터
대표적인 어댑터가 not1(), not2(), bind1st(), bind2nd()입니다.
bind1st(), bind2nd()등은 바인더라고도 합니다.
어댑터는 함수자 predicate를 다른 형태의 predicate로 변환하는 일을 합니다.
Boost 쪽에는 STL처럼 복잡하지 않고 어댑터 기능을 간단하고 강력하게 지원합니다.
각 어댑터의 사용 예제부터 보겠습니다.
bind1st()의 예제입니다.
이 어댑터는 두 인자를 받는 predicate를 하나의 인자를 받는 predicate로 변환합니다.
또, 왼쪽 인자를 고정시키고 오른쪽 인자를 매개 변수로 취하는 predicate를 반환합니다.
#include <iostream>
#include <functional>
using namespace std;
void main()
{
binder1st< less<int> > binder = bind1st(less<int>(), 10 );
// binder는 어댑터(bind1st() )에 의해 변환된 predicate입니다.
cout << binder(5) <<':'<< less<int>()(10, 5) << endl; // 두 문장이 동일합니다.
cout << binder(10) <<':'<< less<int>()(10, 10) << endl;// 두 문장이 동일합니다.
cout << binder(20) <<':'<< less<int>()(10, 20) << endl;// 두 문장이 동일합니다.
cout << "=====위와 같음=====" << endl;
cout << bind1st(less<int>(), 10 )(5) <<':'<< less<int>()(10, 5) << endl;// 같다.
cout << bind1st(less<int>(), 10 )(10) <<':'<< less<int>()(10, 10) << endl;// 같다.
cout << bind1st(less<int>(), 10 )(20) <<':'<< less<int>()(10, 20) << endl;// 같다.
}
- 0:0
0:0
1:1
=====위와 같음=====
0:0
0:0
1:1
bind1st()의 왼쪽 인자는 변환하기 위한 predicate이며 오른쪽 인자는 변환후 고정시킬 왼쪽에 값입니다.
이제 bind2nd() 예제를 보도록 하겠습니다.
bind1st()와 동일한 역할을 합니다.
다른 점은 오른쪽 인자를 고정하고 왼쪽 인자를 매개 변수로 취하는 predicate를 반환합니다.
#include <iostream>
#include <functional>
using namespace std;
void main()
{
binder2nd< less<int> > binder = bind2nd(less<int>(), 10 );
cout << binder(5) <<':'<< less<int>()( 5, 10) << endl; // 두 문장이 동일합니다.
cout << binder(10) <<':'<< less<int>()(10, 10) << endl;// 두 문장이 동일합니다.
cout << binder(20) <<':'<< less<int>()(20, 10) << endl;// 두 문장이 동일합니다.
cout << "==========" << endl;
cout << bind2nd(less<int>(), 10 )(5) <<':'<< less<int>()(5, 10) << endl;// 같다.
cout << bind2nd(less<int>(), 10 )(10) <<':'<< less<int>()(10, 10) << endl;// 같다.
cout << bind2nd(less<int>(), 10 )(20) <<':'<< less<int>()(20, 10) << endl;// 같다.
}
- 1:1
0:0
0:0
==========
1:1
0:0
0:0
쉽죠~~잉! ㅡㅡ;
not1()과 not2()는 bind1st()나 bind2nd로 변환한 predicate를 NOT하는 역할을 하는 어댑터입니다.
예제를 보도록 하겠습니다.
#include <iostream>
#include <functional>
using namespace std;
void main( )
{
binder2nd< less<int> > binder = bind2nd(less<int>(), 10 );
unary_negate< binder2nd<less<int> > > unegate = not1(binder);
cout << unegate(5) <<':'<< not1(binder)(5) <<':'<< not1( bind2nd(less<int>(), 10) )(5) << endl; //모두 같다.
cout << unegate(10) <<':'<< not1(binder)(10) <<':'<< not1( bind2nd(less<int>(), 10) )(10) << endl;//모두 같다.
cout << unegate(20) <<':'<< not1(binder)(20) <<':'<< not1( bind2nd(less<int>(), 10) )(20) << endl;//모두 같다.
}
- 0:0:0
1:1:1
1:1:1
단지, 한 인자를 매개 변수로 받는 predicate를 NOT 하는 predicate를 반환합니다.
아래 예제는 MSDN의 예제코드입니다. 참고하세요.
#include <vector>
#include <functional>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
vector<int> v1;
vector<int>::iterator Iter;
int i;
for (i = 0; i <= 7; i++)
{
v1.push_back(5 * i);
}
cout << "The vector v1 = ( ";
for (Iter = v1.begin(); Iter != v1.end(); Iter++)
cout << *Iter << " ";
cout << ")" << endl;
vector<int>::iterator::difference_type result1;
// Count the elements greater than 10
result1 = count_if(v1.begin(), v1.end(), bind2nd(greater<int>(), 10));
cout << "The number of elements in v1 greater than 10 is: "
<< result1 << "." << endl;
vector<int>::iterator::difference_type result2;
// Use the negator to count the elements less than or equal to 10
result2 = count_if(v1.begin(), v1.end(),
not1(bind2nd(greater<int>(), 10)));
cout << "The number of elements in v1 not greater than 10 is: "
<< result2 << "." << endl;
}
- The vector v1 = ( 0 5 10 15 20 25 30 35 )
The number of elements in v1 greater than 10 is: 5.
The number of elements in v1 not greater than 10 is: 3.
아~! 성의 없죠? ㅡㅡ;;
네 어댑터가 모두 비슷비슷하므로 하나만 구현해 보도록 하겠습니다.
이제 마지막으로 bind1st()함수와 비슷한 함수를 만들어 보도록 하겠습니다.
실제 bind1st()는 몇 가지 멤버를 더 가지고 있지만, 주요 코드는 아래 예제와 같습니다.
#include <iostream>
#include <functional>
using namespace std;
template<typename PredType,typename ArgType>
class Binder1st
{
//... 다른 정보를 표현하기 위한 멤버....
PredType pred;
ArgType left;
public:
Binder1st(const PredType& _pred,const ArgType& _left):pred(_pred),left(_left) { }
bool operator() ( const ArgType& right )
{
return left < right;
}
};
template<typename PredType,typename ArgType>
Binder1st< PredType,ArgType > Bind1st(const PredType& pred, const ArgType& left)
{
return Binder1st<PredType,ArgType>( pred, left );
}
void main( )
{
Binder1st< less<int>, int > binder = Bind1st(less<int>(), 10 );
cout << binder(5) <<':'<< less<int>()(10, 5) << endl; // 두 문장이 동일합니다.
cout << binder(10) <<':'<< less<int>()(10, 10) << endl;// 두 문장이 동일합니다.
cout << binder(20) <<':'<< less<int>()(10, 20) << endl;// 두 문장이 동일합니다.
cout << "==========" << endl;
cout << Bind1st(less<int>(), 10 )(5) <<':'<< less<int>()(10, 5) << endl;// 같다.
cout << Bind1st(less<int>(), 10 )(10) <<':'<< less<int>()(10, 10) << endl;// 같다.
cout << Bind1st(less<int>(), 10 )(20) <<':'<< less<int>()(10, 20) << endl;// 같다.
}
- 0:0
0:0
1:1
==========
0:0
0:0
1:1
Bind1st()라는 함수는 왼쪽 인자를 고정시키고 오른쪽 인자를 매개변수로 취하는 함수자 클래스(Binder1st) 객체를 반환합니다. 이 Binder1st 객체가 변환된 predicate입니다.
출처 : http://blog.daum.net/coolprogramming/76