首先我们来了解一下最基本的函数对象的应用。
先来看STL源码:
//priority_queue模板源码:
template<class _Ty,
class _Container = vector<_Ty>,
class _Pr = less<typename _Container::value_type> >
class priority_queue
{ // priority queue implemented with a _Container
public:
explicit priority_queue(const _Pr& _Pred)
: c(), comp(_Pred)
{
//To use the comparator functor
//bool b = comp(t1, t2);
}
protected:
_Container c; // the underlying container
_Pr comp; // the comparator functor
};
可见_Pr为一种类型,可以为函数指针类型,也可以为类类型。
当为函数指针类型时,必须显式的传入对象,如:
typedef bool (*myfunc)(int , int);
bool testFuncPointer(int i, int j)
{
if (i < j)
return true;
return false;
}
priority_queue<int, myfunc> q(testFuncPointer);
当为类对象时,不需要传入,因为_Pr comp会初始化一个对象出来,继而调用该函数对象的()操作符。
如:
priority_queue<int, greater<int>> q;
但有的人说了:我非要传进去一个函数对象进去不可,这样写。
priority_queue<int> q(less<int>());
priority_queue<int> q(less<int>);错
此种情况为类模板,但是泛型函数,内部书写方式如下:
比如sort:
template<class _RanIt,
class _Diff,
class _Pr> inline
void _Sort(_RanIt _First, _RanIt _Last, _Diff _Ideal, _Pr _Pred)
{
//_Pred(t1, t2);
}
不再有如同上述模板类中的private成员的构造函数,所以_Pred必须传如对象
bool UDgreater ( int elem1, int elem2 )
{
return elem1 > elem2;
}
sort( v1.begin( ), v1.end( ), greater<int>( ) );
sort( v1.begin( ), v1.end( ), greater<int>);错
sort( v1.begin( ), v1.end( ), UDgreater );
另外,更多的函数对象技术,比如否定器,绑定器之类的,去看源代码理解吧。
Tags:Pred一元谓词,BinPred二元谓词,Cmp比较操作,Op一元操作,BinOp二元操作,bind2nd是一个函数,binder2nd是一个类模板等等等等。
附:模仿STL源码自己实现堆,依据传入的cmp去指明是最大堆还是最小堆。
//less是最小堆,即top()返回最小的一个
template<typename T, typename cmp=less<T>>
class MyHeap
{
public:
MyHeap(cmp _cmp = cmp());
MyHeap(T arr[], int len, cmp _cmp = cmp());
const T& top()const
{
assert(m_size > 0);
return m_data[0];
}
T &top()
{
assert(m_size > 0);
return m_data[0];
}
void pop();
int size()const{return m_size;}
void push(const T &val);
private:
void make_heap();
void fix_from_top(int root);
void _swap(T &a, T &b){T tmp = a; a = b; b = tmp;}
void fix_from_bottom(int child);
cmp m_cmp;
static const int MAXSIZE = 1024;
T m_data[MAXSIZE];
int m_size;
};
template<typename T, typename cmp>
MyHeap<T, cmp>::MyHeap(T arr[], int len, cmp _cmp)
:m_cmp(_cmp)
{
assert(len <= MAXSIZE);
memcpy(m_data, arr, sizeof(T)*len);
m_size = len;
make_heap();
}
template<typename T, typename cmp>
MyHeap<T, cmp>::MyHeap(cmp _cmp /* = less<T> */)
:m_size(0)
{
}
template<typename T, typename cmp>
void MyHeap<T, cmp>::make_heap()
{
int end = m_size-1;
for (int i = (end-1)/2; i >= 0; --i)
{
fix_from_top(i);
}
}
template<typename T, typename cmp>
void MyHeap<T, cmp>::fix_from_top(int root)
{
int range = m_size-1;
T val = m_data[root];
int father = root;
int son = father*2+1;
while (son <= range)
{
if(son + 1 <= range && !m_cmp(m_data[son], m_data[son+1]))
++ son;
if (!m_cmp(m_data[father], m_data[son]))
{
_swap(m_data[father], m_data[son]);
father = son;
son = father*2+1;
}
else
break;
}
}
template<typename T, typename cmp>
void MyHeap<T, cmp>::pop()
{
assert(m_size>0);
-- m_size;
m_data[0] = m_data[m_size];
fix_from_top(0);
}
template<typename T, typename cmp>
void MyHeap<T, cmp>::push(const T &val)
{
assert(m_size < MAXSIZE-1);
m_data[m_size] = val;
fix_from_bottom(m_size);
++ m_size;
}
template<typename T, typename cmp>
void MyHeap<T, cmp>::fix_from_bottom(int child)
{
T val = m_data[child];
int father = (child-1)/2;
while (father >= 0)
{
if (!m_cmp(m_data[father], m_data[child]))
{
_swap(m_data[father], m_data[child]);
child = father;
if (child > 0)
father = (child-1)/2;
else
father = -1;
}
else
break;
}
}