#include <boost/smart_ptr.hpp>#include <boost/mpl/list.hpp>#include <boost/function.hpp>#include <typeinfo>#include <map>#include <iostream>using namespace boost;class TypeInfoProxy { public: TypeInfoProxy(const std::type_info * t) : ti(t) {} const std::type_info * ti;};inline bool operator<(const TypeInfoProxy & lhs, const TypeInfoProxy & rhs) { return lhs.ti->before(*rhs.ti) != 0;}inline bool operator>(const TypeInfoProxy & lhs, const TypeInfoProxy & rhs) { return rhs.ti->before(*lhs.ti) != 0;}inline bool operator<=(const TypeInfoProxy & lhs, const TypeInfoProxy & rhs) { return !(rhs > lhs);}inline bool operator>=(const TypeInfoProxy & lhs, const TypeInfoProxy & rhs) { return !(rhs < lhs);}inline bool operator==(const TypeInfoProxy & lhs, const TypeInfoProxy & rhs) { return ((*lhs.ti) == (*rhs.ti)) != 0;}inline bool operator!=(const TypeInfoProxy & lhs, const TypeInfoProxy & rhs) { return ((*lhs.ti) != (*rhs.ti)) != 0;}template <typename T, typename TokenType>class ICreator { public: virtual shared_ptr<T> create(void * args) = 0; virtual ~ICreator() {}};template <typename T>struct Package {};template <typename U1>struct Package<mpl::list<U1> > { U1 arg1;};template <typename U1, typename U2>struct Package<mpl::list<U1, U2> > { U1 arg1; U2 arg2;};template <typename T, typename TypeList, typename TokenType>class ConcreteCreator : public ICreator<T, TokenType> {};template <typename T, typename TokenType>class ConcreteCreator<T, mpl::list<>, TokenType> : public ICreator<T, TokenType> { public: typedef function<shared_ptr<T> (void)> FunctorType; ConcreteCreator(FunctorType functor) : functor_(functor) {} virtual shared_ptr<T> create(void *) { return functor_(); } virtual ~ConcreteCreator() {} private: FunctorType functor_;};template <typename T, typename TokenType, typename U1>class ConcreteCreator<T, mpl::list<U1>, TokenType> : public ICreator<T, TokenType> { public: typedef function<shared_ptr<T> (U1)> FunctorType; typedef Package<mpl::list<U1> > PackageType; ConcreteCreator(FunctorType functor) : functor_(functor) {} virtual shared_ptr<T> create(void * ptr) { PackageType * package = reinterpret_cast<PackageType *>(ptr); return functor_(package->arg1); } virtual ~ConcreteCreator() {} private: FunctorType functor_;};template <typename T, typename TokenType, typename U1, typename U2>class ConcreteCreator<T, mpl::list<U1, U2>, TokenType> : public ICreator<T, TokenType> { public: typedef function<shared_ptr<T> (U1, U2)> FunctorType; typedef Package<mpl::list<U1, U2> > PackageType; ConcreteCreator(FunctorType functor) : functor_(functor) {} virtual shared_ptr<T> create(void * ptr) { PackageType * package = reinterpret_cast<PackageType *>(ptr); return functor_(package->arg1, package->arg2); } virtual ~ConcreteCreator() {} private: FunctorType functor_;};template <typename T, typename TokenType>class Factory { public: shared_ptr<T> create(TokenType type_token) { KeyType key = std::make_pair(type_token, &typeid(void)); CreatorMap::iterator itr = creator_map_.find(key); if (itr == creator_map_.end()) throw std::runtime_error("No registered creator"); return (itr->second)->create(0); } template <typename U1> shared_ptr<T> create(TokenType type_token, U1 a1) { KeyType key = std::make_pair(type_token, &typeid(mpl::list<U1>)); CreatorMap::iterator itr = creator_map_.find(key); if (itr == creator_map_.end()) throw std::runtime_error("No registered creator"); Package<mpl::list<U1> > package = { a1 }; return (itr->second)->create(&package); } template <typename U1, typename U2> shared_ptr<T> create(TokenType type_token, U1 a1, U2 a2) { KeyType key = std::make_pair(type_token, &typeid(mpl::list<U1, U2>)); CreatorMap::iterator itr = creator_map_.find(key); if (itr == creator_map_.end()) throw std::runtime_error("No registered creator"); Package<mpl::list<U1, U2> > package = { a1, a2 }; return (itr->second)->create(&package); } void register_creator(TokenType type, function<shared_ptr<T> (void)> func) { CreatorPtr ptr(new ConcreteCreator<T, mpl::list<>, TokenType>(func)); KeyType key = std::make_pair(type, &typeid(void)); creator_map_[key] = ptr; } template <typename U1> void register_creator(TokenType type, function<shared_ptr<T> (U1)> func) { CreatorPtr ptr(new ConcreteCreator<T, mpl::list<U1>, TokenType>(func)); KeyType key = std::make_pair(type, &typeid(mpl::list<U1>)); creator_map_[key] = ptr; } template <typename U1, typename U2> void register_creator(TokenType type, function<shared_ptr<T> (U1, U2)> func) { CreatorPtr ptr(new ConcreteCreator<T, mpl::list<U1, U2>, TokenType>(func)); KeyType key = std::make_pair(type, &typeid(mpl::list<U1, U2>)); creator_map_[key] = ptr; } private: typedef std::pair<TokenType, TypeInfoProxy> KeyType; typedef shared_ptr<ICreator<T, TokenType> > CreatorPtr; typedef std::map<KeyType, CreatorPtr> CreatorMap; CreatorMap creator_map_;};struct Shape { virtual void print(void) = 0; virtual ~Shape() {}};typedef shared_ptr<Shape> ShapePtr;struct Square : Shape { Square(int side) : side(side) {} void print(void) { std::cout << "I'm a square of size " << side << "!\n"; } static ShapePtr creator(int s) { return ShapePtr(new Square(s)); } int side;};struct Rectangle : Shape { Rectangle(int h, int w) : h(h), w(w) {} void print(void) { std::cout << "I'm a rectangle of sides " << h << " and " << w << "!\n"; } static ShapePtr creator(int h, int w) { return ShapePtr(new Rectangle(h, w)); } int h, w;};int main(int, char **) { Factory<Shape, int> shape_factory; shape_factory.register_creator(0, function<ShapePtr (int)>(&Square::creator)); shape_factory.register_creator(1, function<ShapePtr (int, int)>(&Rectangle::creator)); ShapePtr square = shape_factory.create(0, 5); square->print(); ShapePtr rect = shape_factory.create(1, 3, 4); rect->print(); return 0;}
This should compile and run on a reasonably recent compiler with boost 1.34.1 installed. Take a look at the creation calls at the end. Now change the second call from shape_factory.create(1, 3, 4) to shape_factory.create(1, 3, 4.0) It will now magically throw an exception because it doesn't know how to handle the double, since the creation handler was installed as (int, int).