Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Welcome Guest | Log In | Register | Benefits
Channels ▼
RSS

Using Template Functions to Customize Library Behavior


March 2001/Using Template Functions to Customize Library Behavior/Listing 4

Listing 4: Combining run-time and compile-time policy customization methods of Listings 2 and 3

//
//---- begin file library.h ----
//

#include <map>
#include <string>
#include <iostream>

typedef void(*policyFunction)();
typedef std::map<const void *, policyFunction> policyMap_t;

// singleton class to manage policies
class Policies {
public:
   void   registerInstance(const void * const v, 
                           const policyFunction func);
   policyFunction isRegistered(const void * const v) const;
   void   policy(const void * const v) const;
   static Policies& instancePolicyMap();
private:
   Policies() {}
   policyMap_t instanceMap_;
};

// member function definitions
void
Policies::registerInstance(const void * const v, 
                           const policyFunction func)
{
   if(v != 0 && func != 0) {
      instanceMap_[v] = func;
   }
}

policyFunction
Policies::isRegistered(const void * const v) const 
{
   policyMap_t::const_iterator iter = instanceMap_.find(v);
   if (iter != instanceMap_.end()) {
      return (*iter).second;
   }
   else {
      return 0;
   }
}

void
Policies::policy(const void * const v) const
{
   if (policyFunction pFunc = isRegistered(v)) {
      pFunc();
   } 
}

Policies&
Policies::instancePolicyMap()
{
   static Policies typeMap;
   return typeMap;
}

// namespace scope function for convenience
Policies& instancePolicyMap() 
{
   return Policies::instancePolicyMap();
}    


template<class Container>
void policy(const Container * const c) 
{
   std::cout << "Performing Compile Time Default Policy" 
             << std::endl;
   std::string obj;
   if (c) 
      obj = c->instanceName;
   else
      obj = "unnamed";
   std::cout << "    on Object: " << obj 
             << std::endl << std::endl;
}    
    
//
//---- begin file container.h ----
//

#include "library.h"
#include <string>
#include <iostream>

template <class ElementType>
class MyContainer {
public:
    MyContainer(const std::string iName) : instanceName(iName) 
    {}
    // class implementation
    // ...
    
    // forwards the policy request
    void doPolicy();
    // a service that uses the policy
    void performService() { doPolicy(); }
    
    const std::string instanceName;
};

// elements for example's sake
template<class T>
struct Element1 {
// ...
};

template<class T>
struct Element2 {
// ...
};

template <class ElementType>
void MyContainer<ElementType>::doPolicy() 
{ 
    policy(this);
}

//
//---- begin file user.cpp ----
//

#include "container.h"


// policy functions used for runtime instance control
void runTimePolicy1()
{
    std::cout << "    runTimePolicy1() executed" << std::endl;
}

void runTimePolicy2()
{
    std::cout << "    runTimePolicy2() executed" << std::endl;
}

void runTimePolicy3()
{
    std::cout << "    runTimePolicy3() executed" << std::endl;
}

// A more specialized function overload for a compile time policy
template<class T>
void policy(const MyContainer<T> * c) 
{
   std::cout 
      << "Performing My Compile Time Policy for "
      << "types of:" << std::endl << "MyContainer<Element1<T>"
      << std::endl;
   std::string obj;
   if (c) 
      obj = c->instanceName;
   else
      obj = "unnamed";
   std::cout << "    on Object: " << obj 
             << std::endl << std::endl;
} 

// A more specialized function overload for instance control
template<class T>
void policy(const MyContainer<Element2<T> > * const c)
{
   std::cout << "Performing Runtime Policy: " 
             << std::endl;

   if (!instancePolicyMap().isRegistered(c)) {
       
      // a per instance strategy would go here
      static unsigned int r = 0;
      switch(++r % 3) {
          case 1:
             instancePolicyMap().
                registerInstance(c, &runTimePolicy1);
             break;
          case 2:
             instancePolicyMap().
                registerInstance(c, &runTimePolicy2);
             break;
          case 0:
          default:
             instancePolicyMap().
                registerInstance(c, &runTimePolicy3);
      }
    }       

   std::string obj;
   if (c) 
       obj = c->instanceName;
   else
       obj = "unnamed";
   std::cout << "    Object: " << obj << std::endl;

   instancePolicyMap().policy(c);
} 
               
           
int main() {

   MyContainer<Element1<int> > 
       c("MyContainer<Element1<int> >");
   MyContainer<Element2<float> > 
       d1("MyContainer<Element2<float> > Instance#1");
   MyContainer<Element2<float> > 
       d2("MyContainer<Element2<float> > Instance#2");
   MyContainer<Element2<float> > 
       d3("MyContainer<Element2<float> > Instance#3");

   c.doPolicy();
   d1.doPolicy();
   d2.doPolicy();
   d3.doPolicy();

   return 0;
}
— End of Listing —

Related Reading


More Insights