第10章 STL函数对象及Lambda

1、Function Object(函数对象)

class FunctionObjectType {
	public:
		void operator() () {
			statements;
	}
}

这种定义形式更为复杂,却有三大有点:

  1. Function object比一般函数更灵巧,因为它可以拥有状态(state)。事实上,对于相同的function object Class你可以拥有两个状态不同的实例(instance)。寻常函数无法做到这一点。
  2. 每个function object都有其类型。因此你可以将function object的类型当做template参数传递,从而指定某种行为。还有一个好处:容器类型也会因为function object的不同而不同。
  3. 执行速度上,function object通常比function pointer更快。

eg 1:以Function Object为排序准则(Sorting Criterion)

Class Person{
	public:
		sting firstname() const;
		string lastname() const;
		...
};

class PersonSortCriterion{
	public:
		bool operator () (const Person& p1, const Person& p2) const {
			return p1.lastname() < p2.lastname() ||
					(p1.lastname()  == p2.lastname() &&
					p1.firstname() < p2.firstname());
		}
};

int main () {
	set<Person, PersonSortCriterion> coll;  //create a set with special sorting criterion
	
	for (auto pos = coll.begin(); pos != coll.end(); ++pos){
		...
	}
	....
}

eg 2: Function Object拥有内部状态(Internal State)

class IntSequence{
	private:
		int value;
	public:
		IntSequence (int initialValue) : value(initialValue) {}
		int operator () ()	{return ++value;}	
};

int main () {
	list<int> coll;
	generate_n (back_inserter(coll),
				9,
				IntSequence(1));		
	generate(next(coll.begin()),
			prev(coll.end()),
			IntSequence(42));
}

2、predicate(判断式),就是返回Boolean值的函数或function object。对STL而言并非所有返回Boolean值的函数都是合法的predicate。

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 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
	PRINT_ELEMENTS(coll, "coll: ");
	list<int>::iterator pos;
	pos = remove_if(coll.begin(), coll.end(), Nth(3));
	coll.erase(pos, coll.end());
	PRINT_ELEMENTS(coll, "3rd removed: ");
}

运行结果

coll: 1 2 3 4 5 6 7 8 9 10
3rd removed: 1 2 4 5 7 8 9 10

两个(而非一个)元素被移除了。因为该算法的常见做法会在其内部保留predicate的一个拷贝

template <typename ForwIter, Typename Predicate>
ForwIter std::remove_if(ForwIter beg, ForeIter 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()查找应被移除的第一个元素。然而,接下来它使用传入的predicate op的拷贝去处理剩余的元素,这时原始状态下的Nth再次被使用,因而会移除剩余元素中的第3个元素,也就是整体的第6个元素。
predicate不应该因为被调用而改变自身状态;predicate的拷贝应该和其正本有着相同的状态。应当将operator()声明为const成员函数。

猜你喜欢

转载自blog.csdn.net/weixin_42205011/article/details/87720533