mem_fun(指針)、mem_fun_ref(引用/對象)。ptr_fun 將函數指針轉為函數對象。bind1st(綁第一參數)、bind2nd(綁第二參數)。※ C++11 起推薦使用 std::bind/Lambda,本文解析經典適配器原理。
template <class Fn, class T>
binder2nd<Fn> bind2nd(const Fn& f, const T& val) {
return binder2nd<Fn>(f, Fn::second_argument_type(val));
}
template <class Fn>
struct binder2nd : unary_function<typename Fn::first_argument_type, typename Fn::result_type> {
Fn op; typename Fn::second_argument_type value;
binder2nd(const Fn& f, const typename Fn::second_argument_type& v) : op(f), value(v) {}
result_type operator()(const argument_type& x) const { return op(x, value); } // 綁定第二參數
};
bind2nd(modulus<int>(), 2)(x) 等價於 x % 2,將二元謂詞轉為一元。
vector<int> v = {1,2,3,4,5};
cout << count_if(v.begin(), v.end(), bind2nd(modulus<int>(), 2)) << endl; // 3 (奇數)
cout << count_if(v.begin(), v.end(), bind1st(less<int>(), 4)) << endl; // 1 (>4)
cout << count_if(v.begin(), v.end(), bind2nd(less<int>(), 4)) << endl; // 3 (<4)
適用於對象/引用容器(vector<Person>)。
class Person {
string name;
public:
Person(const string& n) : name(n) {}
void print() const { cout << name << endl; }
void printWithPrefix(const string& pre) const { cout << pre << name << endl; }
};
vector<Person> vp = {Person("tom"), Person("jerry")};
// 無參成員函數 → 一元函數對象
for_each(vp.begin(), vp.end(), mem_fun_ref(&Person::print));
// 一參成員函數 → 二元 → bind2nd 綁第二參數 → 一元
for_each(vp.begin(), vp.end(), bind2nd(mem_fun_ref(&Person::printWithPrefix), "person: "));
適用於指針容器(vector<Person*>),內部用 ptr->func() 調用。
vector<Person*> vpp = {new Person("tom"), new Person("jerry")};
for_each(vpp.begin(), vpp.end(), mem_fun(&Person::print));
for_each(vpp.begin(), vpp.end(), bind2nd(mem_fun(&Person::printWithPrefix), "person: "));
// strcmp 返回 0 相等,非 0 不等
char* arr[] = {"", "BBB", "CCC"};
vector<char*> vs(arr, arr+2);
auto it = find_if(vs.begin(), vs.end(), bind2nd(ptr_fun(strcmp), "")); // 找第一個非空串
if (it != vs.end()) cout << *it << endl; // BBB
// 邏輯取反 not1
bool check(int x) { return x < 3; }
int a[] = {1,2,3,4,5};
auto it2 = find_if(a, a+5, not1(ptr_fun(check))); // 找第一個 >=3
cout << *it2 << endl; // 3
| 適配器 | 輸入 | 輸出 | 核心 operator() |
|---|---|---|---|
| bind2nd | 二元函數對象 + 值 | 一元函數對象 | op(x, bound_val) |
| mem_fun_ref | 成員函數指針 | 函數對象 | (obj.*pmf)() 或 (obj.*pmf)(arg) |
| mem_fun | 成員函數指針 | 函數對象 | (ptr->*pmf)() 或 (ptr->*pmf)(arg) |
| ptr_fun | 函數指針 | 函數對象 | func(args...) |
// Lambda 完全替代
for_each(vp.begin(), vp.end(), [](const Person& p){ p.print(); });
for_each(vp.begin(), vp.end(), [](const Person& p){ p.printWithPrefix("person: "); });
find_if(vs.begin(), vs.end(), [](char* s){ return strcmp(s, "") != 0; });
find_if(a, a+5, [](int x){ return x >= 3; });
Lambda 更直觀、類型推導自動、無需記憶適配器規則,生產代碼首選。