글
C++11에서 STL의 bind와 Boost::bind를 같이 사용할 때 아래와 같이 사용하면 이름 충돌이 발생할 수 있습니다.
#include <functional>
using namespace std::placeholders;
#include <boost/bind.hpp>
int f(int, int);
auto g = std::bind(f, _1, 42); // _1 때문에 에러 발생
해결 방법은 이름 공간을 정확하게 지정하면 됩니다.
auto g = std::bind(f, std::placeholders::_1, 42);
namespace ph = std::placeholders;
auto g = std::bind(f, ph::_1, 42);
글
표준 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
댓글