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 —