태터데스크 관리자

도움말
닫기
적용하기   첫페이지 만들기

태터데스크 메시지

저장하였습니다.

[boost]boost.bind - 파트 1

Posted 2009/02/02 10:56


댓글 하나가 운영자에겐 커다란 힘이 됩니다!

어디에 쓰이는고 하면, 컨테이너의 객체들을 들 쑤시고 싶을 때, 함수 객체를 사용해야 할 때, 일일이 함수 객체를 만들어 주기 귀찮을 때, 주로 사용 된다.

bind 는 std::bindlst 와 std::bind2nd를 보다 일반화 시킨 함수이다.. bind 는 임의의 함수, 함수 포인터, 함수 객체, 멤버 함수를 함수 객체로 만들 수 있으며, 원하는 위치에 원하는 값을 전달 시킬 수 있는 함수 객체를 만들어 준다. (요구 조건 또한 없다. 묶고 싶다면 bind 라고 외워도 될 정도..)

바인드의 가장 기초가 되는 사용법을 알아보면

view plaincopy to clipboardprint?

  1. #include <boost/bind.hpp>   
  2.   
  3. using boost::bind;   
  4.   
  5. int f(int a, int b)   
  6. {   
  7.     return a + b;   
  8. }   
  9.   
  10. int g(int a, int b, int c)   
  11. {   
  12.     return a + b + c;   
  13. }   
  14.   
  15. int main()   
  16. {      
  17.     bind( f, 1, 2 ) ;   // == f( 1, 2)   
  18.     bind( g, 1, 2, 3 ); // == g( 1, 2, 3 )         
  19. }  

여기서 첫번째 바인드 함수 호출 시, 리턴값은 f(1,2) 처럼 행동하는 함수 객체를 리턴하며, 두번째 bind 함수 호출시 g( 1, 2, 3 ) 처럼 행동하는 함수 객체를 리턴 한다. 여기서 1,2,3 은 g의 매개변수의 자리와 상응 되는 자리에 들어 가게 된다. 그러니까 고정된 f(1,2)  또는 g(1,2,3 ) 을 수행 하는 함수 객체를 만들어 리턴시켜 준다.

이 기능만으론 bind 라 할 수 없을 것이다.

다음 소스 코드를 보자.

  1. #include <boost/bind.hpp>   
  2.   
  3. using boost::bind;   
  4.   
  5. int f(int a, int b)   
  6. {   
  7.     return a + b;   
  8. }   
  9.   
  10. int g(int a, int b, int c)   
  11. {   
  12.     return a + b + c;   
  13. }   
  14.   
  15. int main()   
  16. {      
  17.     bind( f, 1, 2 ) ;   // == f( 1, 2)   
  18.     bind( g, 1, 2, 3 ); // == g( 1, 2, 3 )     
  19.   
  20.     int x = 3;   
  21.     int y = 4;   
  22.     int z = 5;   
  23.   
  24.     bind(f, _2, _1)(x, y);                 // f(y, x)   
  25.     bind(g, _1, 9, _1)(x);                 // g(x, 9, x)   
  26.     bind(g, _3, _3, _3)(x, y, z);          // g(z, z, z)   
  27.     bind(g, _1, _1, _1)(x, y, z);          // g(x, x, x)     
  28. }  

 이 코드의 24, 25, 26, 27 라인을 보면, 어떻게 사용 하는지 감이 올 것이다. 각 상응 되는 자리에 변수를 지정 해서 대입 할 수 있다는 것을 보여 준다.

그렇다면 _2 와 _1 은 무슨 것일까? _N 는 전달 되는 인수 목록의 N 번째 자리의 인수를 _N 이 써진 곳에 대입 하겠다는 것을 의미한다. 이것은 내가 원하는 형태로 함수의 매개변수 순서를 변경 할 수 있다는 것을 뜻한다.( 만약 요구 되는 함수의 매개변수 순서를 바꾸어야만 한다면, 이렇게 바꾸어서 쓸 수 있따는 것을 의미한다. )

그러므로 bind(f, _2, _1)(x,y) 는 f( y, x ) 가 되는 것이다. .. 정말 환상적이지 않는가? 

마지막으로 27라인의 bind(g, _1, _1, _1)(x, y, z); 의 bind 리턴은 g( x, x, x ) 처럼 만들어, 3개의 인수를 받는 함수를 1개의 인수를 받는 함수객체로 변경 할 수 있다는 것을 의미한다.(나머지 인자는 무시 된다) .. 정말 환상적이다.


bind의 의미를 다시 해석하기 위한 코드

  1. #include <boost/bind.hpp>   
  2. #include <iostream>   
  3.   
  4. using boost::bind;   
  5.   
  6. int f(int a, int b)   
  7. {   
  8.     return a + b;   
  9. }   
  10.   
  11. int main()   
  12. {      
  13.     int i = 5;   
  14.     int x = 3;   
  15.   
  16.     // 사용법 1   
  17.     // f의 1번째 매개변수에 i를, 2번째 매개변수에 x를 대입된 결과를 리턴   
  18.     std::cout << bind(f, i, _1)(x);   
  19.   
  20.     // 사용법 2   
  21.     // f의 1번째 매개변수에 i를, 2번째 매개변수에 x를 대입된 함수 객체를 리턴   
  22.     bind(f, i, x );   
  23.   
  24.     // 사용법 3   
  25.     // f의 1번째 매개변수에 1을, 2번째 매개변수에 i를 대입된 함수 객체를 리턴   
  26.     bind(f, 1, i );   
  27.   
  28.     // 사용법 4   
  29.     // f의 1번째 매개변수에 x를, 2번째 매개변수에 x를 대입된 결과를 리턴   
  30.     std::cout << bind(f, _1, x )( x );   
  31. }  

 주석을 달아 두었다. 한가지 다시 짚어 본다면, bind는 함수 객체를 리턴 하는 함수라는 것이다. 만약 리턴 값을 얻고 싶다면, 그 함수 객체를 operator() 를 수행해야 한다. bind가 너무 유연하다보니, 여기서 햇갈렸다.


총 정리 코드

  1. #include <boost/bind.hpp>   
  2. #include <boost/ref.hpp>   
  3.   
  4. #include <iostream>   
  5.   
  6. using boost::bind;   
  7. using boost::ref;   
  8. using boost::cref;   
  9.   
  10. int f(int a, int b)   
  11. {   
  12.     return a + b;   
  13. }   
  14.   
  15. int main()   
  16. {      
  17.     int i = 5;   
  18.   
  19.     // operator()( 5, x ) 로 수행 되는 함수 객체 리턴     
  20.     bind(f, i, _1);   
  21.   
  22.     // operator()(&i, x ) 로 수행 되는 함수 객체 리턴   
  23.     // 만약 f의 내부에서 i를 변경시킨다면 i 에 5가 아닌 다른 값이 들어 갈 수 있다.   
  24.     bind(f, ref(i), _1);   
  25.   
  26.     // 이것은 무엇이지?   
  27.     bind(f, cref(42), _1)(1, 2, 3, 4, 5, 6, 7, 8, 9 );   
  28. }  

이 코드의 ref 와 cref 는 전달 된 인자를 reference 로 바꾸거나 const reference 로 바꾸어 주는 함수이다. 눈 여겨 볼 것은 마지막 27 라인의 코드이다. 여기서 _1 부분, 즉 1만 인식되고, 나머지는 무시 된다. 이것은 만들어진 함수 객체에 최대 9개까지인자로 전달 될 수 있다는 것을 의미한다.


여기까지가 일반 함수를 bind 하여, 객체 함수를 만드는 방법이다. 그렇다면, 함수 포인터는 어떻게 할 수 있을까? 다음 코드를 보자.

  1. #include <boost/bind.hpp>   
  2.   
  3. #include <iostream>   
  4.   
  5. using boost::bind;   
  6.   
  7. int f(int a, int b)   
  8. {   
  9.     return a + b;   
  10. }   
  11.   
  12. int main()   
  13. {      
  14.     // 함수 포인터형 선언   
  15.     typedef int (*FUNCPOINTER)( intint );   
  16.        
  17.     // 포인터에 f 를 대입   
  18.     FUNCPOINTER funcpointer = f;   
  19.   
  20.     // 결과 확인   
  21.     std::cout << bind( funcpointer, 1, 2 )();   
  22. }  

 

.. 이것으로 일반 함수나, 함수 포인터를 어떻게 bind 시켜서 함수 객체로 만들고, 변형 시키는 방법을 알아 보았다. 다음 파트 2에선 함수 객체를 어떻게 해보는지 알아 본다.


총평

역시 공부는 정리할 때 더 많이 알아 가는것 같다. STL 를 사용 한다면, bind 를 꼭 알고 넘어가야 하는 넘어 가야겠다는 생각이 든다. 템플릿 함수이다 보니, .. 그 소스 코드가 매우 보기 힘들지만, 이 정도는 만들 수 있어야 " 나 템플릿 좀 써봤지" 라고 말 할 수 있을 것 같다.

출처 : http://ikpil.com/695

위의 정보가 도움이 되셨나요? 그렇다면 댓글 하나만 남겨주세요.
댓글 하나가 운영자에겐 커다란 힘이 됩니다!

Write your message and submit
« PREV : 1 : ... 120 : 121 : 122 : 123 : 124 : 125 : 126 : 127 : 128 : ... 436 : NEXT »