Introduction
mem_fun
is a very useful STL helper template function which takes advantage of the class member function matching the template parameters. Most of the time, mem_fun
can be directly used without the construction class. But in some special sophisticated algorithmd, the mem_fun
can not be called directly, and the construction classes mem_fun_t
/cont_mem_fun_t
(for non parameter class member functions) and mem_fun1_t
/const_mem_fun1_t
(for one parameter class member functions) must be used to create the mem_fun
object.
In this article, the sample project shows how to create mem_fun
object with mem_fun_t
/mem_fun1_t
class.
Case Study
In the demo project, a unique algorithm is designed to complete the tasks:
- Sort the list with specific sort order.
- Calculate the summation of list.
- Above two tasks must be completed in a single procedure.
Before designing the main algorithm, two helper template functions are given out; the first is the comparison of two objects:
template<typename TType, typename TFunc> class TComparsion
{
public:
TComparsion(const TFunc& func,
bool bAsc = true):m_fFunc(func), m_bAsc(bAsc){};
bool operator () (TType* t1, TType* t2)
{
if(m_bAsc)
return (m_fFunc(t1) < m_fFunc(t2));
else
return (m_fFunc(t2) < m_fFunc(t1));
}
private:
TFunc m_fFunc;
bool m_bAsc;
};
The second is the summation of the objects:
template<typename TType, typename TFunc, typename TFuncOut>
class TSummation
{
public:
TSummation(const TFunc& func,const TFuncOut tVal = 0)
:m_fFunc(func), m_tSummation(tVal){};
void operator()(TType* t)
{
if(t)
{
m_tSummation += m_fFunc(t);
}
}
operator TFuncOut(){return m_tSummation;}
private:
TFunc m_fFunc;
TFuncOut m_tSummation;
};
In this template class, the type conversion operator must be given out for retrieving the summation from STL for_each
functor.
The main algorithm is designed as:
template <typename TList, typename TCmp, typename TSum,
typename TSumVal>class TSortSumAlgor
{
public:
TSortSumAlgor(const TCmp& fcmp, const TSum& fsum)
:m_Fcmp(fcmp), m_Fsum(fsum){};
TSumVal operator()(TList& t)
{
std::stable_sort<TList::iterator>(t.begin(), t.end(), m_Fcmp);
return std::for_each<TList::iterator>(t.begin(), t.end(), m_Fsum);
}
private:
TCmp m_Fcmp;
TSum m_Fsum;
};
In stlalgor.cpp, the sample classes demonstrate the application of this algorithm.
The member function "Get
" of class CDblCounter
and "GetStr
" of class CStrCounter
can be used as the functor for the templates TComparsion
and TSummation
. To pass these two class member functions as the template parameters, the STL mem_fun
must be used as the member function of TComparsion
and TSummation
. But, in this algorithm implementation, the mem_fun
can not be called directly in these templates, so the construction class mem_fun_t
must be used to create the mem_fun
object being passed to the algorithm.
The following code:
typedef mem_fun_t<double, CDblCounter> CDblMemFuncT;
......
typedef mem_fun_t<string, CStrCounter> CStrMemFuncT;
defines the concrete construction class for passing CDblCounter::Get
and CStrCounter::GetStr
to mem_fun
. These two definitions are very important for the algorithm calling mem_fun
.
The following definitions give out the concrete comparison and summation class in which the mem_fun
objects, which adapt CDblCounter::Get
and CStrCounter::GetStr
, are implemented as the class member functions.
typedef TComparsion<CDblCounter, CDblMemFuncT> CDblCmpFunctor;
typedef TSummation<CDblCounter, CDblMemFuncT, double> CDblSumFunctor;
......
typedef TComparsion<CStrCounter, CStrMemFuncT> CStrCmpFunctor;
typedef TSummation<CStrCounter, CStrMemFuncT, string> CStrSumFunctor;
Finally the concrete algorithm classes are defined as:
typedef TSortSumAlgor<CDblArray, CDblCmpFunctor,
CDblSumFunctor, double> CDblAglor;
......
typedef TSortSumAlgor<CStrArray, CStrCmpFunctor,
CStrSumFunctor, string> CStrAglor;
The figure shows the steps of applying mem_fun
in a complicated algorithm:
The algorithm can be applied as the code shown in stlalgor.cpp:
CDblArray dList1;
...
...
...
CDblCmpFunctor fCmp(std::mem_fun<double, CDblCounter>
(&CDblCounter::Get), true);
CDblSumFunctor fSum(std::mem_fun<double, CDblCounter>
(&CDblCounter::Get), 0.0);
CDblAglor pAglor(fCmp, fSum);
double dSum = pAglor(dList1);
...
...
...
CStrArray sList;
...
...
...
CStrCmpFunctor sfCmp(std::mem_fun<string, CStrCounter>
(&CStrCounter::GetStr), true);
CStrSumFunctor sfSum(std::mem_fun<string, CStrCounter>
(&CStrCounter::GetStr), "Programming Language:");
CStrAglor sAglor(sfCmp, sfSum);
string sSum = sAglor(sList);
In templdefs.h and stlalgor.cpp, the use of mem_fun1_t
is also demonstrated.
template<typename TType, typename TFunc,
typename TFuncOut, typename TParam>class TSummation1
{
public:
TSummation1(const TFunc& func, const TParam tParam,
const TFuncOut tVal = 0):m_fFunc(func), m_tParam(tParam),
m_tSummation(tVal){};
void operator()(TType* t)
{
if(t)
{
m_tSummation += m_fFunc(t, m_tParam);
}
}
operator TFuncOut(){return m_tSummation;}
private:
TFunc m_fFunc;
TParam m_tParam;
TFuncOut m_tSummation;
};
...
...
...
typedef mem_fun1_t<double, CDblCounter, double> CDblMemFunc1T;
typedef TSummation1<CDblCounter, CDblMemFunc1T,
double, double> CDblSum1Functor;
...
...
...
CDblSum1Functor fSum1(std::mem_fun<double, CDblCounter,
double>(&CDblCounter::Calc), 8.0, 0.0);
dSum = for_each(dList1.begin(), dList1.end(), fSum1);
Updated Sample Code (June 2005)
In the updated sample code, the new template and class demonstrate how to apply bind1st
/bind2nd
helper template function in the algorithm design and implementation. The key points in designing the functor template for bind1st
/bind2nd
are that the first_argument_type
, second_argument_type
, result_type
must be explicitly defined.
The sample code with regards to bind1st
/bind2nd
is:
template<typename TList, typename TType,
typename TValue, typename TFunc>class TSearch
{
public:
TSearch(const TFunc& func): m_fFunc(func){};
TType operator()(TList& tl, const TValue& tv)
{
TType pRet = 0;
TList::iterator iter;
iter = std::find_if<TList::iterator>(tl.begin(),
tl.end(), std::bind2nd(m_fFunc, tv));
if(iter != tl.end())
{
pRet = (*iter);
}
return pRet;
}
private:
TFunc m_fFunc;
};
template<typename TType1, typename TType2,
typename TReturn, typename TFunc>class TBinder
{
public:
typedef TType1 first_argument_type;
typedef TType2 second_argument_type;
typedef TReturn result_type;
TBinder(const TFunc& func):m_fFunc(func){};
result_type operator()(first_argument_type tc,
second_argument_type tv) const
{
result_type vRet;
vRet = m_fFunc(tc, tv);
return vRet;
}
private:
TFunc m_fFunc;
};
template<typename TClass, typename TValue,
typename TFunc>class TEqualFunctor
{
public:
TEqualFunctor(const TFunc& func):m_fFunc(func){};
bool operator()(TClass tc, const TValue& tv) const
{
bool bRet = false;
bRet = (tv == m_fFunc(tc));
return bRet;
}
private:
TFunc m_fFunc;
};
...
...
...
typedef vector<CPersonInfo*> CPersonArray;
typedef TSeqDeletor<CPersonInfo> CPersonDel;
typedef TDealloc<CPersonArray, CPersonDel> CPersonClean;
typedef const_mem_fun_t<int, CPersonInfo> CPersonMemT;
typedef TEqualFunctor<CPersonInfo*, int, CPersonMemT> CPersonFinder;
typedef TBinder<CPersonInfo*, int, bool, CPersonFinder> CPersonChecker;
typedef TSearch<CPersonArray, CPersonInfo*,
int, CPersonChecker> CPersonSearch;
...
...
...
Conclusion
The mem_fun
is a very powerful functor to manipulate and process the class object's behavior and functionality in the algorithm procedure. Properly building the mem_fun
object is very important and sometimes the mem_fun_t
/mem_fun1_t
construction class must be used to create the mem_fun
object.