Click here to Skip to main content
15,886,723 members
Articles / Programming Languages / C++
Article

How to use STL helper template function mem_fun in sophisticated algorithms

Rate me:
Please Sign up or sign in to vote.
4.54/5 (7 votes)
24 Jun 20052 min read 68.9K   351   16   2
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:

  1. Sort the list with specific sort order.
  2. Calculate the summation of list.
  3. 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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Canada Canada
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralVery useful to know. Pin
WREY6-Mar-04 5:52
WREY6-Mar-04 5:52 
GeneralRe: Very useful to know. Pin
Zhaohui Xing (Joey)6-Mar-04 6:33
Zhaohui Xing (Joey)6-Mar-04 6:33 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.