How to use STL helper template function mem_fun in sophisticated algorithms






4.54/5 (7 votes)
Mar 4, 2004
2 min read

69272

351
The article gives a sample that demonstrates the use of mem_fun in some special cases.
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) // Ascending sort return (m_fFunc(t1) < m_fFunc(t2)); else // Descending sort return (m_fFunc(t2) < m_fFunc(t1)); } private: TFunc m_fFunc; // The member function object bool m_bAsc; // Sort order, true: ascending sort, false: descending sort };
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){}; // Overload the operator() void operator()(TType* t) { if(t) { m_tSummation += m_fFunc(t); } } // Type cast operator TFuncOut(){return m_tSummation;} private: TFunc m_fFunc; // The member function object TFuncOut m_tSummation; // The return value };
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) { // Sort the list std::stable_sort<TList::iterator>(t.begin(), t.end(), m_Fcmp); // Get the summation return std::for_each<TList::iterator>(t.begin(), t.end(), m_Fsum); } private: TCmp m_Fcmp; // Comparsion functor TSum m_Fsum; // Summation functor };
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){}; // Overload the operator() void operator()(TType* t) { if(t) { m_tSummation += m_fFunc(t, m_tParam); } } operator TFuncOut(){return m_tSummation;} private: TFunc m_fFunc; // The member function object TParam m_tParam; // The member function parameter TFuncOut m_tSummation; // The return value }; ... ... ... 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){}; // Overload the operator() 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; // The member function object }; template<typename TType1, typename TType2, typename TReturn, typename TFunc>class TBinder { public: // The three key type definitions typedef TType1 first_argument_type; typedef TType2 second_argument_type; typedef TReturn result_type; TBinder(const TFunc& func):m_fFunc(func){}; // Overload the operator() 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; // The member function object }; template<typename TClass, typename TValue, typename TFunc>class TEqualFunctor { public: TEqualFunctor(const TFunc& func):m_fFunc(func){}; // Overload the operator() bool operator()(TClass tc, const TValue& tv) const { bool bRet = false; bRet = (tv == m_fFunc(tc)); return bRet; } private: TFunc m_fFunc; // The member function object }; ... ... ... 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.