函数对象在算法、容器方面用的很普遍,这部分作者给出了5个Item,着重强调如何以STL方式来使用这些函数对象。
void qsort(void *base, size_t nmemb, size_t size, int (*cmpfcn)(const void*, const void*));函数参数cmpfcn将函数体拷贝(按值传递)给函数sqort。STL的约定是传给函数和从函数返回时函数对象是按值传递的。如果通过引用传递和返回,那么编译器可能不能通过,如下面我们对for_each指定显式模板实参:
for_each<DequeIntIter, DoSomething&>(di.begin(), di.end(), d);按值传递意味着我们的函数对象需要满足下两个条件:
template<typename T> class BPFC : public unary_function<T, void> { // BPFC = “Big Polymorphic private: Widget w; // too many members Int x; ... public: virtual void operator()(const T& val) const; // virtual function, ... // cut off! };建立一个包含一个指向实现类的指针的小而单态的类,然后把所有数据和虚函数放到实现类:
template<typename T> class BPFCImpl public unary_function<T, void> { private: Widget w; // all members int x; // ... virtual ~BPFCImpl(); virtual void operator()(const T& val) const; friend class BPFC<T>; }; template<typename T> class BPFC : public unary_function<T, void> { // monomorphic private: BPFCImpl<T> *pImpl; // pointe to BPFCImpl public: void operator()(const T& val) const // nonvirtual { pImpl->operator() (val); } ... };上面的实现方式就是所谓的”Bridge模式“。由于上诉函数对象含有指针类型,所以必须考虑复制、拷贝、析构函数做了正确的事情。
class BadPredicate : public unary_function<Widget, bool> { public: BadPredicate(): timesCalled(0) {} bool operator()(const Widget&) { return ++timesCalled == 3; } private: size_t timesCalled; };我们将它应用于vector:
vector<Widget> vw; vw.erase(remove_if(vw.begin(), vw.end(), BadPredicate()), vw.end()); //// remove the third Widget;这段代码表面上看没有问题,但是很多STL实现不仅删去第三个对象,还会删去第六个对象!我们来分析一下可能的一种remove_if实现:
template <typename FwdIterator, typename Predicate> FwdIterator remove_if(FwdIterator begin, FwdIterator end, Predicate p) { begin = find_if(begin, end, p); if (begin == end) return begin; else { FwdIterator next = begin; return remove_copy_if(++next, end, begin, p); } }最开始p的timesCalled初始化为0,然后 按值传递 给find_if,在find_if中执行了三次,控制权转移到remove_copy_if,而此也是将p拷贝给它, 而timeCalled仍为0,在remove_copy_if第三次调用predicate时也会返回ture。
bool isInteresting(const Widget *pw); list<Widget*>::iterator i = find_if(widgetPtrs.begin(), widgetPtrs.end(), not1(ptr_func(isInteresting)));为了让isInteresting可适配,我们在前面加上ptr_func。
template<typename T> class MeetsThreshold: public std::unary_function<Widget, bool>{ private: const T threshold; public: MeetsThreshold(const T& threshold); bool operator()(const Widget&) const; ... };
list<Widget*> lpw; ... for_each(lpw.begin(), lpw.end(), mem_fun(&Widget::test));
list<Widget> lpw; ... for_each(lpw.begin(), lpw.end(), mem_fun_ref(&Widget::test));同时,mem_fun和mem_fun_ref都提供了一些typedef。
template<> struct std::less<Widget> // specialization : public std::binary_function<Widget, Widget, bool> { bool operator()(const Widget& lhs, const Widget& rhs) const { return lhs.maxSpeed() < rhs.maxSpeed(); } };这样的设计缺乏合理性,通常来说,修改std里的组件是禁止的。
struct MaxSpeedCompare: public binary_function<Widget, Widget, bool> { bool operator()(const Widget& lhs, const Widget& rhs) const { return lhs.maxSpeed() < rhs.maxSpeed(); } }; multiset<Widget, MaxSpeedCompare> widgets;而multiset<Widget>是按默认less<Widget>来排序的,也就是使用operator<。