首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ STL 函數適配器詳解:bind2nd、mem_fun_ref、ptr_fun 實戰與源碼剖析

     編輯:關於C++

函數適配器三大類

  1. 針對成員函數:mem_fun(指針)、mem_fun_ref(引用/對象)。
  2. 針對普通函數:ptr_fun 將函數指針轉為函數對象。
  3. 參數綁定:bind1st(綁第一參數)、bind2nd(綁第二參數)。

※ C++11 起推薦使用 std::bind/Lambda,本文解析經典適配器原理。

bind2nd 源碼機制

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,將二元謂詞轉為一元。

實戰案例 1:統計奇數 / 大於值

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)

mem_fun_ref 成員函數適配器

適用於對象/引用容器(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: "));

mem_fun 指針容器版本

適用於指針容器(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: "));

ptr_fun 普通函數適配器

// 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...)

現代替代方案 (C++11+)

// 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 更直觀、類型推導自動、無需記憶適配器規則,生產代碼首選。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved