본문 바로가기

프로그래밍

[펌] Boost 로 C++0x의 라이브러리 「TR1」을 미리 사용 해 보자 (4)

[중급] bind  function

 ind

표준 C++ 라이브러리가 제공하는 다양한 함수에는 1개(혹은2개)의 인수를 주는 함수 오브젝트를 인도하는 것이 다수 있습니다.

 

정수는 몇 개?

  1. #include <iostream>
    #include <algorithm>

  2. using namespace std;


  3. // n  정수라면 true를 돌려준다

  4. bool is_positive( int n)

    {

  5. return n > 0;

  6. }


  7. int main()

    {

  8. const int N = 8;

  9. int data[N] = { -3, -2, -1, 0, 1, 2, 3, 4 };

  10.     /* count_if(first, last, pred):

  11. * first이상 last미만의 범위에 있  x에 대해

  12. * pred(*x)  true (!=0)  되는 것의 개수를 돌려준다 */ 

  13. cout << count_if(data, data+N, &is_positive) << " positives\n" ;

  14. }


실행 결과

4 positives

 

그럼 같이 표준 C++ 라이브러리의 함수 오브젝트 less 를 사용 하여 상기의 is_positive 로 옮겨지지 않는가 생각해 봅시다.

함수 오브젝트 less 의 멤버 함수 operator() 는 인수를 2개 취하여 제1인수가 제2인수보다 작으면 true 를 돌려줍니다.

함수 오브젝트 less

  1. std::less< int > int_less;

  2. bool result = int_less(1,2); // true 

  3. result = int_less(2,1); // false 

  4. result = int_less(2,2); // false

 

 less 를 방금 전의 알고리즘 :count_if 의 제3인수에 사용하기 위해 binder1st  less::operator() 의 제1인수를0으로 속박(고정) 합니다.

bind1st/bind2nd에 의한 속박

  1. #include <iostream>
    #include <algorithm>
    #include <functional>

  2. using namespace std;


  3. int main()

    {

  4. const int N = 8;

  5. int data[N] = { -3, -2, -1, 0, 1, 2, 3, 4 };

  6. // 제1인수를 0으로 속박 하는 것으로, 

  7. // 인수가 정수라면 true를 돌려주는 함수 오브젝트가 된다. 

  8. cout << count_if(data, data+N, bind1st(less< int >(),0))

  9. << " positives\n" ;

  10. // 제 2인수를 0으로 속박 하면 정수라면 true를 돌려준다. 

    cout << count_if(data, data+N, bind2nd(less< int >(),0))

  11. << " negatives\n" ;

  12. }

실행 결과

4 positives

3 negatives


그러면 「-3 이상, 3 미만의 요소 수」를 요구하려면 어떻게 할까요.

mid가 lo 이상, hi 미만이라면 true를 돌려준다

  1. template <typename T>

  2. bool in_between(T lo, T mid, T hi) {

  3. return lo <= mid && mid < hi;

  4. }


이런 함수 in_between 을 준비하여 제1인수를 -3, 제3인수를 3으로 속박 하면 좋겠습니다만 표준 C++이 준비해 주고 있는 바인더(속박 함수)는 2항 함수 오브젝트에 대한 bind1st  bind2nd 뿐입니다.

TR1은 이와 같이 제한의 어려운 바인더를 일반 화해, operator() 에게 주는 임의의 인수를 속박 하는 범용 바인더 : bind를 제공해 줍니다.


bind를 사용해 -3 이상, 3 미만의 요소를 센다

 

  1. #include <iostream>

  2. #include <algorithm>

  3. #include <functional>

  4. #include <boost/tr1/functional.hpp>

  5. using namespace std;


  6. // lo <= mid < hi 이라면 true를 돌려준다

  7. template <typename T>

  8. bool in_between(T lo, T mid, T hi) {

  9. return lo <= mid && mid < hi;

  10. }


  11. int main()

    {

  12. const int N = 8;

  13. int data[N] = { -3, -2, -1, 0, 1, 2, 3, 4 };

  14. // 플레이스홀더: _1, _2, ... 를 유효하게 한다 

  15. using namespace tr1::placeholders;

  16. // in_between의 제1,제3인수를 각각 -3,3으로 속박 한다 

  17. cout << count_if(data, data+N,

  18. tr1::bind(&in_between< int >, -3, _1, 3))

  19. << " numbers are [-3,3)\n" ;

  20. }

 실행 결과
6 numbers are [-3,3)

플레이스홀더의 수/위치/순서는 자유롭게 선택할 수 있기 때문에 이하의 샘플과 같이 3항 함수의 인수 1개를 속박 해  2항 함수로 할 수도 있습니다.

    요소의 소트

  1. #include <iostream>

  2. #include <algorithm>

  3. #include <functional>

  4. #include <boost/tr1/functional.hpp>


  5. using namespace std;


  6. // 승순/내림차순의 어느 쪽에도 사용할 수 있는 비교 함수

  7. template <typename T>

  8. bool compare(T x, T y, bool descend) {

  9. return descend ? (x < y) : (y < x);

  10. }


  11. int main()

    {

  12. const int N = 8;

  13. int data[N] = { 0, -1, 1, -2, 2, -3, 3, 4 };

  14. using namespace tr1::placeholders;

  15. // 내림차순로 소트 sort의 제3인수는 2항 함수 오브젝트 

  16. sort(data, data+N, tr1::bind(&compare< int >, _1, _2, false ));

  17. for ( int i = 0; i < N; ++i ) cout << data[i] << ' '; cout << endl;

  18. // 승순으로 소트 

  19. sort(data, data+N, tr1::bind(&compare< int >, _1, _2, true ));

  20. for ( int i = 0; i < N; ++i ) cout << data[i] << ' '; cout << endl;

  21. // 이것도 역시 승순으로 소트(플레이스홀더의 순서에 주목) 

  22. sort(data, data+N, tr1::bind(&compare< int >, _2, _1, false ));

  23. for ( int i = 0; i < N; ++i ) cout << data[i] << ' '; cout << endl;

  24. }

 실행 결과
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 는 클래스의 멤버 함수마저도 바인드 해 줍니다.

     멤버 함수의 바인드

  1. #include <iostream>

  2. #include <string>

  3. #include <boost/tr1/functional.hpp>


  4. using namespace std;


  5. class Sandwitch {

  6. string mid_;

  7. public :

  8. Sandwitch( const string& mid) : mid_(mid) {}

  9. string make( const string& head, const string& tail) const {

  10. return head + mid_ + tail;

  11. }

  12. };


  13. int main()

    {

  14. Sandwich s( " and " );

  15. Sandwich* p = &s;

  16. using namespace tr1::placeholders;

  17. // s.make("boys,"girls") 

  18. cout << tr1::bind(&Sandwich::make, s, "boys" , _1)( "girls" ) << endl;

  19. // p->make("ladies","gentlemen") 

  20. cout << tr1::bind(&Sandwich::make, p, "ladies" , _1)( "gentlemen" )

  21. << endl;

  22. // p->make("black","white") 

  23. cout << tr1::bind(&Sandwich::make, p, _2, _1)( "while" ,"black" )

  24. << endl;

  25. // s.make("hit","away") 

  26. cout << tr1::bind(&Sandwich::make, _1, "hit" , "away" )(s) << endl;

  27. // p->make("adam","eve"); 

  28. cout << tr1::bind(&Sandwich::make, _1, "adam" , "eve" )(p) << endl;

  29. // s.make("love","peace") 

  30. cout << tr1::bind(&Sandwich::make, _1, _2, _3)(s, "love" ,"peace" )

  31. << endl;

  32. }

 실행 결과
boys and girls
ladies and gentlemen
black and while
hit and away
adam and eve
love and peace

function

그런데, 범용 바인더 bind 에 의해서 생성된 함수 오브젝트를 변수로 격납하여 얼마든지 알고리즘으로 사용해 돌리는 것을 생각해 봅시다. 그러기 위해서는 bind 가 생성한 함수 오브젝트의 '형'을 가지는 변수를 선언하지 않으면 안됩니다.

    bind의 생성하는 함수 오브젝트의 '형'

  1. 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
 은 함수 오브젝트의 범용적인'형'으로서 기능합니다.

    함수 오브젝트를 통일적으로 취급한다

  1. #include <iostream>

  2. #include <algorithm>

  3. #include <functional>

  4. #include <boost/tr1/functional.hpp>


  5. using namespace std;


  6. // x < y 이라면 true를 돌려준다

  7. bool less_int( int x, int y) {

  8. return x < y;

  9. }


  10. // 승순/내림차순 어느 쪽에도 사용할 수 있는 비교 함수

  11. template <typename T>

  12. bool compare(T x, T y, bool descend) {

  13. return descend ? (x < y) : (y < x);

  14. }


  15. int main()

    {

  16. const int N = 8;

  17. int data[N] = { 0, -1, 1, -2, 2, -3, 3, 4 };

  18. // template 인수가 조금 특수. 

  19. // 반환값 (변수,변수...) 라고 하는 형식. 

  20. tr1::function< bool ( int ,int)> comp;

  21. // 승순으로 소트 

  22. using namespace tr1::placeholders;

  23. comp = tr1::bind(&compare< int >, _1, _2, true );

    sort(data, data+N, comp);

  24. for ( int i = 0; i < N; ++i ) cout << data[i] << ' '; cout << endl;

  25. // 같은 승순으로 소트 

  26. comp = &less_int;

  27. sort(data, data+N, comp);

  28. for ( int i = 0; i < N; ++i ) cout << data[i] << ' '; cout << endl;

  29. // 이것도 역시 내림차순으로 소트 

  30. comp = less< int >();

  31. sort(data, data+N, comp);

  32. for ( int i = 0; i < N; ++i ) cout << data[i] << ' '; cout << endl;

  33. }


 

 

번역 후기........

번역된 글을 퍼 갈 때는 꼭 아래의 글을 같이 복사 해 주세요.

번역은 원 저자에게 허락을 받은 것은 아니므로 상업적으로 사용할 경우에는 꼭 원저자에게 허락을 받기를 바랍니다.

출처 : http://codezine.jp/a/article/aid/2158.aspx

 

번역 :   choi_2.jpg   최흥배 ( jacking75@gmail.com ).

             (주) 다이슨 파이퍼스튜디오에서 서버 프로그래머로 근무 중.