Question

I have the following factory function:

std::auto_ptr<IPath> PathFactory(std::string const& branch_type, CPathModel const& path_model)
{
   using namespace boost::assign;
   using namespace boost::phoenix::placeholders;

   typedef boost::function<IPath* (CPathModel const&)> PathFactoryFunction;
   typedef boost::unordered_map<std::string, PathFactoryFunction> FactoryMap;

   static FactoryMap factory_map = map_list_of<std::string, PathFactoryFunction>
      ("plu",           &phx::new_<CPluPath>)
      ("time_of_day",   &phx::new_<CTimeOfDayPath>)
      ("probability",   &phx::new_<CProbabilityPath>)
      ;

   std::auto_ptr<IPath> new_path;

   FactoryMap::const_iterator it = factory_map.find(branch_type);
   if (it != factory_map.end())
   {
      new_path.reset(it->second(path_model));
   }

   return new_path;
}

This code doesn't compile, and please note that I'm using C++03. What I'm trying to do here is create a mapping of strings to small function objects that can allocate an object of a specific type. Each object takes a single construction parameter of the same type (CPathModel const&).

phx::new_ has several overloads, so it probably isn't the best idea to refer to it directly, but I'm hoping everyone can help me find a way to use boost::phoenix to clean up this code and make the mapping work elegantly.

It seems easier at this point to just define a small template class with an overloaded () operator that takes the parameter and just does new T(p1) inside. But this is boilerplate and seems simple enough that boost must have a nice solution somewhere...

Was it helpful?

Solution

Phoenix is utility for lazy functors.

You need none here (there is nary an expression template in sight).

So, you can make your own factory method template:

template <typename PathType> IPath* make_path(CPathModel const& model) { 
    return new PathType(model);
}

And use it:

static FactoryMap factory_map = map_list_of<std::string, PathFactoryFunction>
  ("plu",           &make_path<CPluPath>)
  ("time_of_day",   &make_path<CTimeOfDayPath>)
  ("probability",   &make_path<CProbabilityPath>)
  ;

Job done.

Although, at this point, there is zero benefit to using the map to lookup the factory. In fact, it's only wasteful. A simple switch[1] would be far superior. More so, because it removes the type erasure (implicit virtual polymorphism) in std::function.

[1] In fact, it would need to be chained ifs, or you can switch on a Perfect Hash

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top