• 仿函数


    仿函数三大妙处:

    1、仿函数比一般函数更灵巧,因为它可以拥有状态。事实上对于仿函数,你可以同时拥有两个状态不同的实体。

    2、每个仿函数都有其型别。因为你可以将仿函数的型别当作template参数来传递,从而指定某种行为模式,容器型别也会因为仿函数的不同而不同。

    3、执行速度上,仿函数通常比函数指针更快。就template概念而言,很多细节在编译期就已确定。

    仿函数是以by value方式传递的好处是,你可以传递常量或暂时表达式,如果不这样设计,就不能传递ClassName(1)这样的表达式(临时对象),至于缺点是无法改变仿函数的状态。因为你改变的只是副本而已。然而我们有时候确实需要存取最终状态。因此,问题在于如何从一个算法中获取结果。

    有两个办法可以从“运用了仿函数”的算法中获取“结果”或“反馈”。

    1、以by reference的方式传递仿函数(仅限参考,不一定管用)

    2、运用for_each()算法的回返值

    例1:by reference(在vs2013上不管用,原因如注释)

    #include <iostream>
    #include <list>
    #include<algorithm>
    #include<iterator>
    
    using namespace std;
    
    
    class IntSequence{
    private:
    	int value;
    public:
    	IntSequence(int initialValue) :value(initialValue){};
    
    	int operator()()
    	{
    		return value++;
    	}
    };
    
    int main()
    {
    	list<int> coll;
    	IntSequence seq(1);
    
    	generate_n<back_insert_iterator<list<int>>, int, IntSequence&>(back_inserter(coll), 4, seq);//在该算法内部,调用了另外的模板                                                                                                   //进行了传值,而不是by reference
    	copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " "));
    	cout << endl;
    
    	generate_n(back_inserter(coll), 4, IntSequence(42));
    	generate_n(back_inserter(coll), 4, seq);
    	copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " "));
    	cout << endl;
    
    	system("pause");
    	return 0;
    }
    

    例2:for_each()

    #include <iostream>
    #include <vector>
    #include<algorithm>
    #include<iterator>
    
    using namespace std;
    
    
    class MeanValue{
    private:
    	long num;
    	long sum;
    
    public:
    	MeanValue() :num(0), sum(0){}
    
    	void operator()(int elem)
    	{
    		num++;
    		sum += elem;
    	}
    
    	double value()
    	{
    		return static_cast<double>(sum) / static_cast<double>(num);
    	}
    };
    
    int main()
    {
    	vector<int> coll;
    	for (int i = 1; i <= 8; ++i)
    	{
    		coll.push_back(i);
    	}
    	MeanValue mv = for_each(coll.begin(), coll.end(), MeanValue());
    	cout <<"mean value"<<mv.value()<< endl;
    
    	system("pause");
    	return 0;
    }
    

    输出:mean value4.5

    一个陷阱:

    #include <iostream>
    #include <list>
    #include<algorithm>
    #include<iterator>
    
    using namespace std;
    
    class Nth{
    private:
    	int nth;
    	int count;
    public:
    	Nth(int n) :nth(n), count(0){}
    
    	bool operator()(int){
    		return ++count == nth;
    	}
    };
    
    
    int main()
    {
    	list<int> coll;
    	for (int i = 1; i <= 9; ++i)
    	{
    		coll.push_back(i);
    	}
    	copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " "));
    	cout << endl;
    	list<int>::iterator pos;
    	pos = remove_if(coll.begin(), coll.end(), Nth(3));
    	coll.erase(pos, coll.end());
    	copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " "));
    	cout << endl;
    	system("pause");
    	return 0;
    }
    

    输出:

    1 2 3 4 5 6 7 8 9
    1 2 4 5 7 8 9   //3和6都被删除了

    下面是remove_if的一般实作:

    template<class ForwIter,class Predicate>
    ForwIter std::remove_if(ForwIter beg, ForwIter end, Predicate op)
    {
     beg = find_if(beg, end, op);
     if (beg == end)
     {
      return beg;
     }
     else
     {
      ForwIter next = beg;
      return remove_copy_if(++next, end, beg, op);
     }
    }
    

    find_if传值,remove_copy_if中op的count从零开始,即在实施删除时又进行了一次删除。

    解决方法:总是将判断式operator()声明为const成员函数。

    预定义的仿函数:

    #include<functional>

    仿函数

    效果

    negate<type>()

    -param

    plus<type>()

    param1+param2

    minus<type>()

    param1-param2

    multiplies<type>()

    param1*param2

    divides<type>()

    param1/param2

    modulus<type>()

    param1%param2

    equal_to<type>()

    param1==param2

    not_equal_to<type>()

    param!=param2

    less<type>()

    param1<param2

    greater<type>()

    param1>param2

    less_equal<type>()

    param1<=param2

    greater_equal<type>()

    param1>=param2

    logical_not<type>()

    !param

    logical_and<type>()

    param1&&param2

    logical_or<type>()

    param1||param2

    函数配接器:

    表达式

    效果

    bind1st(op,value)

    op(value,param)

    bind2nd(op,value)

    op(param,value)

    not1

    !op(param)

    not2

    !op(param1,param2)

    针对成员函数而设计的函数配接器

    mem_fun_ref(op)

    调用op,那是某对象的一个const成员函数

    mem_fun(op)

    调用op,那是某对象指针的一个const成员函数

    针对一般函数而设计的函数配接器

    ptr_fun(op)

    op(param)

    op(param1,param2)

    例子:mem_fun_ref

    vs2013不要求成员函数为const

    </pre><pre class="cpp" name="code">class Person{
    private:
    	string name;
    public:
    	Person(string na) :name(na){}
    	void print() const{
    		cout << name << endl;
    	}
    	void printWithPrefix(string prefix)const
    	{
    		cout << prefix << name << endl;
    	}
    };
    list<Person> coll;
    for_each(coll.begin(), coll.end(), mem_fun_ref(&Person::print));
    for_each(coll.begin(), coll.end(), bind2nd(mem_fun_ref(&Person::printWithPrefix), "person:"));
    list<Person*> coll;
    for_each(coll.begin(), coll.end(), mem_fun(&Person::print));
    for_each(coll.begin(), coll.end(), bind2nd(mem_fun(&Person::printWithPrefix), "person:"));
    

    mem_fun_ref和mem_fun两者都能以无参数或单参数方式来调用成员函数。
    ptr_fun:

    假设有一个能对每个参数实施某种检测的全局函数如下:

    bool check(int elem)
    

    如果要搜寻第一个令检查失败的元素,可以如下:

    pos=find_if(coll.begin(),coll.end(),not1(ptr_fun(check)));

    这里ptr_fun不可省略,因为not1()需要用到仿函数提供的某些特殊型别。

    第二种用法,你有一个双参数全局函数,又想把它当成一个单参数函数使用

    pos=find_if(coll.begin(),coll.end(),bind2nd(ptr_fun(strcmp),""));

  • 相关阅读:
    VS 2008 和 .NET 3.5 Beta 2 发布了
    搭建.NET 3.0环境
    Expression Studio和Silverlight学习资源、安装问题汇总
    Discuz! NT官方社区
    VS2005中ajax安装指南[转]
    IT人 不要一辈子靠技术生存(转)
    Discuz!NT2.5发布 正式版同步开源
    VS2005下开发Silverlight 1.1翻译加补充
    自动化测试案例
    [原]JavaScript必备知识系列开篇
  • 原文地址:https://www.cnblogs.com/ggzone/p/4052429.html
Copyright © 2020-2023  润新知