• C++之ptr_fun、mem_fun和mem_fun_ref


    一、背景引入

    如果我有一个函数f和一个对象x,我希望在x上调用f,而且我在x的成员函数之外。C++给我三种不同的语法
    来实现这个调用:

    // 语法#1:当f是一个非成员函数
    f(x);     
    
    // 语法#2:当f是一个成员函数 ,而且x是一个对象或一个对象的引用             
    x.f();    
                  
    // 语法#3:当f是一个成员函数,而且p是一个对象的指针                     
    p->f();                                  

    现在,假设我有一个可以测试Widget的函数,

     // 测试w,如果没通过,就标记为“failed”
    void test(Widget& w);          
                                
    而且我有一个Widget的容器:

     // vw容纳Widget
    vector<Widget> vw;  

                       
    要测试vw中的每个Widget,我很显然可以这么使用for_each:

     // 调用#1(可以编译)
    for_each(vw.begin(), vw.end(), test); 

     
    但想象test是一个Widget的成员函数而不是一个非成员函数,也就是说,Widget支持自我测试:
    class Widget {
    public:

    // 进行自我测试;如果没通过,就把*this标记为“failed”
            void test();                                            
    };


    在一个完美的世界,我也将能使用for_each对vw中的每个对象调用Widget::test:

     // 调用#2(不能编译)
    for_each(vw.begin(), vw.end(), &Widget::test);  

          
    实际上,如果世界真的完美,我将也可以使用for_each来在Widget*指针的容器上调用Widget::test:
    list<Widget*> lpw; 

    // lpw容纳Widget的指针,调用#3(也不能编译)                           
    for_each(lpw.begin(), lpw.end(), &Widget::test); 

     二、使用方法        

    也许现在清楚为什么mem_fun和mem_fun_ref存在了。它们让成员函数(通常必须使用句法#2或者#3来调用的)使用句法1调用。

     

    1、mem_fun和mem_fun_ref用法

    // 同上

    ist<Widget*> lpw;                              
    ...

     // 这个现在可以编译了
    for_each(lpw.begin(), lpw.end(), mem_fun(&Widget::test));      

     

    for_each接受一个mem_fun_t类型的对象,持有一个Widget::test的指针。对于在lpw里的每个Widget*指针,for_each使用语法#1

     

    如果你有一个支持重画的Widget类:

    1 class Widget {
    2 public:
    3   ...
    4   void redraw() const;
    5   ...
    6 };

    list<Widget> lw;

    for_each( lw.begin(),  lw.end(), mem_fun_ref(&Widget::redraw))

      总的来说,mem_fun适配语法#3——也就是当和Widget*指针配合时Widget::test要求的——到语法1,也就是for_each用的。因此也不奇怪像mem_fun_t这样的类被称为函数对象适配器。知道这个不应该使你惊讶,完全类似上述的,mem_fun_ref函数适配语法#2到语法#1

     2、ptr_fun用法

    for_each(vw.begin(), vw.end(), test); // 同上,调用#1;这个可以编译

    for_each(vw.begin(), vw.end(), ptr_fun(test));  // 可以编译,行为,就像上面的调用#1
      

    如果你关于什么时候使用ptr_fun什么时候不使用而感到困惑,那就考虑每当你传递一个函数给STL组件时都使用它。STL将不在乎, 并且没有运行期的惩罚。可能出现的最坏的情况就是一些读你代码的人当看见不必要的ptr_fun使用时,可能会扬起眉毛。我认为,那有多让你操心依赖于你对扬起眉毛的敏感性。


    一个与ptr_fun有关的可选策略是只有当你被迫时才使用它。如果当typedef是必要时你忽略了它,你的编译器将退回你的代码。然后你得返回去添加它

     3、举例

    例1:

     1 #include <algorithm>  
     2 #include <functional>  
     3 #include <iostream>  
     4  
     5 using namespace std;  
     6  
     7 int sum(int arg1, int arg2)  
     8 {  
     9     std::cout<< "arg1 = " << arg1 << std::endl;  
    10     std::cout<< "arg2 = " << arg2 << std::endl;  
    11  
    12     int sum = arg1 + arg2;  
    13     std::cout << "sum = " << sum << std::endl;  
    14  
    15     return sum;  
    16 }
    17  
    18 int main(int argc, char *argv[], char *env[])
    19 {  
    20     bind1st(ptr_fun(sum), 1)(2);        // the same as sum(1,2)  
    21     bind2nd(ptr_fun(sum), 1)(2);        // the same as sum(2,1)  
    22  
    23     system("pause");
    24     return 0;
    25 }

    结果:

    例2:

     1 #include<iostream>
     2 #include<vector>
     3 #include<algorithm>
     4 #include<functional>
     5 #include<string>
     6 
     7 using namespace std;
     8 
     9 int main()
    10 {
    11     vector<const char*> coll;
    12     vector<const char*>::iterator iter1, iter2;
    13 
    14     coll.push_back("lan");
    15     coll.push_back("zhi");
    16     coll.push_back("hui");
    17     coll.push_back("is");
    18     coll.push_back("a");
    19     coll.push_back("good");
    20     coll.push_back("boy!");
    21 
    22     for (iter1 = coll.begin(); iter1 != coll.end(); ++iter1)
    23     {
    24         cout << *iter1 << " ";
    25     }
    26     cout << endl;
    27 
    28     iter2 = find_if(coll.begin(), coll.end(), not1(bind2nd(ptr_fun(strcmp), "hui")));//hui与coll中所有字符串比较,如果相同,则反相后输出
    29 
    30     if (iter2 != coll.end())
    31     {
    32         cout << "Found: " << *iter2 << endl;
    33     }
    34     else
    35     {
    36         cout << "Not Found" << endl;
    37     }
    38 
    39     return 0;
    40 }

    结果:

    本文来自博客园,作者:Mr-xxx,转载请注明原文链接:https://www.cnblogs.com/MrLiuZF/p/14081052.html

  • 相关阅读:
    第07组 Beta冲刺(3/5)
    第07组 Beta冲刺(2/5)
    第07组 Beta冲刺(1/5)
    第07组 Alpha事后诸葛亮
    第07组 Alpha冲刺(6/6)
    第07组 Alpha冲刺(5/6)
    【置顶】CSP/NOIP 2020 (高二游记)
    【置顶】CSP/S 2019退役祭
    【置顶】一些关于停课的感想(随时更新,连着前一篇博客)11/11~11/15
    【置顶】我的2018~2019信息学之路
  • 原文地址:https://www.cnblogs.com/MrLiuZF/p/14081052.html
Copyright © 2020-2023  润新知