[중급] bind 와 function
ind
표준 C++ 라이브러리가 제공하는 다양한 함수에는 1개(혹은2개)의 인수를 주는 함수 오브젝트를 인도하는 것이 다수 있습니다.
정수는 몇 개?
#include <iostream>
#include <algorithm>using namespace std;
// n 이 정수라면 true를 돌려준다
bool is_positive( int n)
{
return n > 0;
}
int main()
{
const int N = 8;
int data[N] = { -3, -2, -1, 0, 1, 2, 3, 4 };
/* count_if(first, last, pred):
* first이상 last미만의 범위에 있 는 x에 대해
* pred(*x) 가 true (!=0) 가 되는 것의 개수를 돌려준다 */
cout << count_if(data, data+N, &is_positive) << " positives\n" ;
}
실행 결과
4 positives
그럼 같이 표준 C++ 라이브러리의 함수 오브젝트 less 를 사용 하여 상기의 is_positive 로 옮겨지지 않는가 생각해 봅시다.
함수 오브젝트 less 의 멤버 함수 operator() 는 인수를 2개 취하여 제1인수가 제2인수보다 작으면 true 를 돌려줍니다.
함수 오브젝트 less
std::less< int > int_less;
bool result = int_less(1,2); // true
result = int_less(2,1); // false
result = int_less(2,2); // false
이 less 를 방금 전의 알고리즘 :count_if 의 제3인수에 사용하기 위해 binder1st 로 less::operator() 의 제1인수를0으로 속박(고정) 합니다.
bind1st/bind2nd에 의한 속박
#include <iostream>
#include <algorithm>
#include <functional>using namespace std;
int main()
{
const int N = 8;
int data[N] = { -3, -2, -1, 0, 1, 2, 3, 4 };
// 제1인수를 0으로 속박 하는 것으로,
// 인수가 정수라면 true를 돌려주는 함수 오브젝트가 된다.
cout << count_if(data, data+N, bind1st(less< int >(),0))
<< " positives\n" ;
// 제 2인수를 0으로 속박 하면 정수라면 true를 돌려준다.
cout << count_if(data, data+N, bind2nd(less< int >(),0))
<< " negatives\n" ;
}
실행 결과
4 positives
3 negatives
그러면 「-3 이상, 3 미만의 요소 수」를 요구하려면 어떻게 할까요.
mid가 lo 이상, hi 미만이라면 true를 돌려준다
template <typename T>
bool in_between(T lo, T mid, T hi) {
return lo <= mid && mid < hi;
}
이런 함수 in_between 을 준비하여 제1인수를 -3, 제3인수를 3으로 속박 하면 좋겠습니다만 표준 C++이 준비해 주고 있는 바인더(속박 함수)는 2항 함수 오브젝트에 대한 bind1st 와 bind2nd 뿐입니다.
TR1은 이와 같이 제한의 어려운 바인더를 일반 화해, operator() 에게 주는 임의의 인수를 속박 하는 범용 바인더 : bind를 제공해 줍니다.
bind를 사용해 -3 이상, 3 미만의 요소를 센다
#include <iostream>
#include <algorithm>
#include <functional>
#include <boost/tr1/functional.hpp>
using namespace std;
// lo <= mid < hi 이라면 true를 돌려준다
template <typename T>
bool in_between(T lo, T mid, T hi) {
return lo <= mid && mid < hi;
}
int main()
{
const int N = 8;
int data[N] = { -3, -2, -1, 0, 1, 2, 3, 4 };
// 플레이스홀더: _1, _2, ... 를 유효하게 한다
using namespace tr1::placeholders;
// in_between의 제1,제3인수를 각각 -3,3으로 속박 한다
cout << count_if(data, data+N,
tr1::bind(&in_between< int >, -3, _1, 3))
<< " numbers are [-3,3)\n" ;
}
실행 결과
6 numbers are [-3,3)
플레이스홀더의 수/위치/순서는 자유롭게 선택할 수 있기 때문에 이하의 샘플과 같이 3항 함수의 인수 1개를 속박 해 2항 함수로 할 수도 있습니다.
요소의 소트
#include <iostream>
#include <algorithm>
#include <functional>
#include <boost/tr1/functional.hpp>
using namespace std;
// 승순/내림차순의 어느 쪽에도 사용할 수 있는 비교 함수
template <typename T>
bool compare(T x, T y, bool descend) {
return descend ? (x < y) : (y < x);
}
int main()
{
const int N = 8;
int data[N] = { 0, -1, 1, -2, 2, -3, 3, 4 };
using namespace tr1::placeholders;
// 내림차순로 소트 ※sort의 제3인수는 2항 함수 오브젝트
sort(data, data+N, tr1::bind(&compare< int >, _1, _2, false ));
for ( int i = 0; i < N; ++i ) cout << data[i] << ' '; cout << endl;
// 승순으로 소트
sort(data, data+N, tr1::bind(&compare< int >, _1, _2, true ));
for ( int i = 0; i < N; ++i ) cout << data[i] << ' '; cout << endl;
// 이것도 역시 승순으로 소트(플레이스홀더의 순서에 주목)
sort(data, data+N, tr1::bind(&compare< int >, _2, _1, false ));
for ( int i = 0; i < N; ++i ) cout << data[i] << ' '; cout << endl;
}
실행 결과
4 3 2 1 0 -1 -2 -3
-3 -2 -1 0 1 2 3 4
-3 -2 -1 0 1 2 3 4
한층 더 bind 는 클래스의 멤버 함수마저도 바인드 해 줍니다.
멤버 함수의 바인드
#include <iostream>
#include <string>
#include <boost/tr1/functional.hpp>
using namespace std;
class Sandwitch {
string mid_;
public :
Sandwitch( const string& mid) : mid_(mid) {}
string make( const string& head, const string& tail) const {
return head + mid_ + tail;
}
};
int main()
{
Sandwich s( " and " );
Sandwich* p = &s;
using namespace tr1::placeholders;
// s.make("boys,"girls")
cout << tr1::bind(&Sandwich::make, s, "boys" , _1)( "girls" ) << endl;
// p->make("ladies","gentlemen")
cout << tr1::bind(&Sandwich::make, p, "ladies" , _1)( "gentlemen" )
<< endl;
// p->make("black","white")
cout << tr1::bind(&Sandwich::make, p, _2, _1)( "while" ,"black" )
<< endl;
// s.make("hit","away")
cout << tr1::bind(&Sandwich::make, _1, "hit" , "away" )(s) << endl;
// p->make("adam","eve");
cout << tr1::bind(&Sandwich::make, _1, "adam" , "eve" )(p) << endl;
// s.make("love","peace")
cout << tr1::bind(&Sandwich::make, _1, _2, _3)(s, "love" ,"peace" )
<< endl;
}
실행 결과
boys and girls
ladies and gentlemen
black and while
hit and away
adam and eve
love and peace
function
그런데, 범용 바인더 bind 에 의해서 생성된 함수 오브젝트를 변수로 격납하여 얼마든지 알고리즘으로 사용해 돌리는 것을 생각해 봅시다. 그러기 위해서는 bind 가 생성한 함수 오브젝트의 '형'을 가지는 변수를 선언하지 않으면 안됩니다.
bind의 생성하는 함수 오브젝트의 '형'
cout << typeid (tr1::bind(&Sandwich::make, _1, _2, _3)).name();
실행 결과
class boost::_bi::bind_t< class std::basic_string< char ,
struct std::char_traits< char >,class std::allocator< char > >,
class boost::_mfi::cmf2< class std::basic_string< char ,
struct std::char_traits< char >,class std::allocator< char > >,
class Sandwich,class std::basic_string< char ,
struct std::char_traits< char >,class std::allocator< char > > const &,
class std::basic_string< char ,struct std::char_traits< char >,
class std::allocator< char > > const &>,
class boost::_bi::list3< class boost::arg<1>,class boost::arg<2>,class boost::arg<3> > >
……터무니없고 복잡한 형태가 만들어져 있습니다. 이것으로는 변수를 선언할 수 없습니다.
클래스 템플릿 function 은 함수 오브젝트의 범용적인'형'으로서 기능합니다.
함수 오브젝트를 통일적으로 취급한다
#include <iostream>
#include <algorithm>
#include <functional>
#include <boost/tr1/functional.hpp>
using namespace std;
// x < y 이라면 true를 돌려준다
bool less_int( int x, int y) {
return x < y;
}
// 승순/내림차순 어느 쪽에도 사용할 수 있는 비교 함수
template <typename T>
bool compare(T x, T y, bool descend) {
return descend ? (x < y) : (y < x);
}
int main()
{
const int N = 8;
int data[N] = { 0, -1, 1, -2, 2, -3, 3, 4 };
// template 인수가 조금 특수.
// 반환값 (변수,변수...) 라고 하는 형식.
tr1::function< bool ( int ,int)> comp;
// 승순으로 소트
using namespace tr1::placeholders;
comp = tr1::bind(&compare< int >, _1, _2, true );
sort(data, data+N, comp);
for ( int i = 0; i < N; ++i ) cout << data[i] << ' '; cout << endl;
// 같은 승순으로 소트
comp = &less_int;
sort(data, data+N, comp);
for ( int i = 0; i < N; ++i ) cout << data[i] << ' '; cout << endl;
// 이것도 역시 내림차순으로 소트
comp = less< int >();
sort(data, data+N, comp);
for ( int i = 0; i < N; ++i ) cout << data[i] << ' '; cout << endl;
}
번역 후기........
번역된 글을 퍼 갈 때는 꼭 아래의 글을 같이 복사 해 주세요.
번역은 원 저자에게 허락을 받은 것은 아니므로 상업적으로 사용할 경우에는 꼭 원저자에게 허락을 받기를 바랍니다.
출처 : http://codezine.jp/a/article/aid/2158.aspx
번역 : 최흥배 ( jacking75@gmail.com ).
(주) 다이슨 파이퍼스튜디오에서 서버 프로그래머로 근무 중.
'프로그래밍' 카테고리의 다른 글
[펌] ACE_Message_Block Pool 만들기 (0) | 2012.08.13 |
---|---|
[펌] Boost 로 C++0x의 라이브러리 「TR1」을 미리 사용 해 보 자 (5) (0) | 2012.08.13 |
[펌] Boost 로 C++0x의 라이브러리 「TR1」을 미리 사용 해 보자 (3) (0) | 2012.08.13 |
[펌] Boost 로 C++0x의 라이브러리 「TR1」을 미리 사용 해 보자 (1) (0) | 2012.08.13 |
[펌] Lock-Free Queue (0) | 2012.08.11 |