c++ for_each 的各种用法

  1. 引入
    先看一段不用for_each 的代码:

    #include<iostream>
    #include<vector>
    #include<algorithm>
    using namespace std;
    
    int main()
    {
        int a[] = { 1, 2, 3, 4};
        vector<int> v(a, a+sizeof(a)/sizeof(int));
        for(vector<int>::iterator itor = v.begin();itor!=v.end();++itor)
        {
            cout<<*itor<<endl;
        }
    }

    其中这句代码:

    for(vector<int>::iterator itor = v.begin();itor!=v.end();++itor)

    略长,如果不常写,倒是很容易手生。
    使用for_each代码就比较简洁。
    for_each()事实上是個function template,其实质如下[effective STL item 41]

    template<typename InputIterator, typename Function>
    Function for_each(InputIterator beg, InputIterator end, Function f) {
      while(beg != end) 
        f(*beg++);
    }

    由以上source可知,for_each()只能配合global function和function object。
    以下将对procedure based、object oriented、generics三种paradigm与for_each()搭配做探讨。

  2. Procedure Based与for_each()搭配
    2.1 不传入参数:
     

    void fun(int i )
    {
        cout<<i<<endl;
    }
    
    int main()
    {
        int a[] = { 1, 2, 3, 4};
        vector<int> v(a, a+sizeof(a)/sizeof(int));
        for_each(v.begin(), v.end(), fun);
    }

    2.2传入参数:
    要传入参数给global function ,需要使用 ptr_fun() 这个 function adapter 将global function 转成function object , 然后再用bind2nd() 将参数bind成一个function object。(这句话好拗口)。
     

    void fun(int i, const char* str)
    {
        cout<<str<<i<<endl;
    }
    
    int main()
    {
        int a[] = { 1, 2, 3, 4};
        vector<int> v(a, a+sizeof(a)/sizeof(int));
        for_each(v.begin(), v.end(), bind2nd(ptr_fun(fun), "Element:"));
    }

    bind2nd 和 ptr_fun看这里:
    bind1st bind2nd的使用
    【STL】ptr_fun详解

    2.3匿名函数输出:
     

    int main()
    {
        int a[] = { 1, 2, 3, 4};
        vector<int> v(a, a+sizeof(a)/sizeof(int));
        for_each(v.begin(), v.end(), [](int str) {cout << str << endl; });
        return 0;
    }

     

  3. Object Oriented 与for_each 搭配
    3.1 不传入参数,使用function object

    #include<iostream>
    #include<vector>
    #include<algorithm>
    #include<typeinfo>
    using namespace std;
    
    struct Play
    {
        void operator () (int i)
        {
            cout<<i<<endl;
        }
    };
    
    int main()
    {
        int a[] = { 1, 3, 4, 5};
        vector<int> vc(a, a+sizeof(a)/sizeof(int));
        for_each(vc.begin(), vc.end(), Play());
    }

    输出是:
     

    1
    3
    4
    5

    这里我有一点疑问, Play() 是怎么用的?
    我给代码加了一点输入,查看建立和销毁对象的过程:
     

    #include<iostream>
    #include<vector>
    #include<algorithm>
    #include<typeinfo>
    using namespace std;
    
    struct Play
    {
        Play()
        {
            cout<<"new a Play"<<endl;
        }
        Play(const Play&)
        {
            cout<<"new a copy Play"<<endl;
        }
        void operator () (int i)
        {
            cout<<i<<endl;
        }
        ~Play()
        {
            cout<<"dispose a Play"<<endl;
        }
    };
    
    int main()
    {
        int a[] = { 1, 3, 4, 5};
        vector<int> vc(a, a+sizeof(a)/sizeof(int));
        for_each(vc.begin(), vc.end(), Play());
        cout<<"See something"<<endl;
    }

    此时输出是:
     

    new a Play
    1
    3
    4
    5
    new a copy Play
    dispose a Play
    dispose a Play
    See something

    可以看到这个过程有两个Play对象生成,但是,用于输出元素的却是第一个对象(重载() 操作符),为什么?
    这时候回去看for_each的源码,就会发现,它的返回值是function,以我的猜测,应该是这样的。Play() 生成一个临时的匿名的Play对象,传入for_each 函数里,然后执行完for_each 函数后,return一个function时,Play用复制构造函数生成一个Play对象,然后两个Play对象的生命周期都结束,于是依次销毁。
    3.2 传入参数:
    可以通过构造函数的技巧传入参数:
     

    #include<iostream>
    #include<vector>
    #include<algorithm>
    #include<typeinfo>
    using namespace std;
    
    struct Play
    {
        const char* str;
        Play(const char* s):str(s) {}
        void operator () (int i)
        {
            cout<<str<<i<<endl;
        }
    };
    
    int main()
    {
        int a[] = { 1, 3, 4, 5};
        vector<int> vc(a, a+sizeof(a)/sizeof(int));
        for_each(vc.begin(), vc.end(), Play("Element:"));
    }

     

  4. Member function 与 for_each 搭配
    4.1 不传入参数:
    通过mem_fun_ref() 这个funtion adapater 将 member funtion 转成 function object。
     

    #include<iostream>
    #include<vector>
    #include<algorithm>
    #include<typeinfo>
    using namespace std;
    
    class Door
    {
    public:
        void open() const
        {
            cout<<"open door horizontally"<<endl;
        }
    };
    
    class DoorController
    {
    protected:
        vector<Door> _doorVec;
    
    public:
        void addDoor(Door door)
        {
            _doorVec.push_back(door);
        }
    
        void openDoor() const
        {
            for_each(_doorVec.begin(), _doorVec.end(), mem_fun_ref(&Door::open));
        }
    };
    
    int main()
    {
        DoorController dc;
        dc.addDoor(Door());
        dc.addDoor(Door());
        dc.openDoor();
    }

    输出:
     

    open door horizontally
    open door horizontally

    值得注意的是,mem_fun_ref() 用在 object 的 member function。若要搭配多态,vector必须放pointer,也就是得使用object pointer的member function,此时得使用mem_fun()将member function转成function object。
    4.2 传入参数:
    要使用 bind2nd
     

    #include<iostream>
    #include<vector>
    #include<algorithm>
    #include<typeinfo>
    using namespace std;
    
    class AbstractDoor
    {
    public:
        virtual void open(const char* str) const = 0; //定义纯虚函数
    
        virtual ~AbstractDoor() {}
    };
    
    class HorizontalDoor: public AbstractDoor
    {
        public:
        void open(const char* str) const
        {
            cout<<str<<"open door horizontally"<<endl;
        }
    };
    
    class VerticalDoor: public AbstractDoor
    {
        public:
        void open(const char* str) const
        {
            cout<<str<<"open door vertically"<<endl;
        }
    
    };
    
    class DoorController
    {
    protected:
        vector<AbstractDoor*> _doorVec;
    
    public:
        void addDoor(AbstractDoor* door)
        {
            _doorVec.push_back(door);
        }
    
        void openDoor() const
        {
            for_each(_doorVec.begin(), _doorVec.end(), bind2nd(mem_fun(&AbstractDoor::open), "Jhon "));
        }
    
        ~DoorController() 
        {
            for_each(_doorVec.begin(), _doorVec.end(), [](AbstractDoor* p)
            {
                delete p;
                p = nullptr;
            });
        }
    };
    
    int main()
    {
        DoorController dc;
        dc.addDoor(new HorizontalDoor());
        dc.addDoor(new VerticalDoor());
        dc.openDoor();
    }

    这里用到了Lambda,我会另讲
    上面用到mem_fun_ref 和 mem_fun ,我不是很明白,参考:
    STL中mem_fun和mem_fun_ref的用法
    引用一句很重要的用法:

    mem_fun_ref的作用和用法跟mem_fun一样,唯一的不同就是:当容器中存放的是对象实体的时候用mem_fun_ref,当容器中存放的是对象的指针的时候用mem_fun。

  5. Generics与for_each()搭配
    5.1 Funtion template

    5.1.1 不传入参数
     

    #include<iostream>
    #include<vector>
    #include<algorithm>
    #include<typeinfo>
    using namespace std;
    
    template<typename T>
    void play(T elem)
    {
        cout<<elem<<endl;
    }
    
    int main()
    {
        int a[] = {1, 3, 4, 5};
        vector<int> vc(a, a+sizeof(a)/sizeof(int));
        for_each(vc.begin(), vc.end(), play<int>);
    }

    5.1.2 传入参数
     

    #include<iostream>
    #include<vector>
    #include<algorithm>
    #include<typeinfo>
    using namespace std;
    
    template<typename T, char str>
    void play(T elem)
    {
        cout<<str<<elem<<endl;
    }
    
    int main()
    {
        int a[] = {1, 3, 4, 5};
        vector<int> vc(a, a+sizeof(a)/sizeof(int));
        for_each(vc.begin(), vc.end(), play<int, 'a'>);
    }

    这里无法传入字串或者别的指针的类型。
    5.2 class template
    5.2.1 不传入参数
     

    #include<iostream>
    #include<vector>
    #include<algorithm>
    #include<functional>
    using namespace std;
    
    template<typename T>
    class Play/*:public unary_function<T, void>*/ //我不懂为什么原文需要这个?
    {
        public:
        void operator() (T elem)
        {
            cout<<elem<<endl;
        }
    };
    int main()
    {
        int a[] = {1, 3, 4, 5};
        vector<int> vc(a, a+sizeof(a)/sizeof(int));
        for_each(vc.begin(), vc.end(), Play<int>());
    }

    5.2 2传入参数
     

    #include<iostream>
    #include<vector>
    #include<algorithm>
    #include<functional>
    using namespace std;
    
    template<typename T, typename V>
    class Play/*:public unary_function<T, void>*/ //我不懂为什么原文需要这个?
    {
        V _str;
        public:
        Play(V str):_str(str) {}
        void operator() (T elem)
        {
            cout<<_str<<elem<<endl;
        }
    };
    int main()
    {
        int a[] = {1, 3, 4, 5};
        vector<int> vc(a, a+sizeof(a)/sizeof(int));
        for_each(vc.begin(), vc.end(), Play<int, const char*>("Element "));
    }

    注:转自小键233的 c++ for_each 用法

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值