Created
June 29, 2011 19:01
-
-
Save pyrtsa/1054616 to your computer and use it in GitHub Desktop.
Object factory v2, using Boost.Phoenix, Boost.Function and Boost.SmartPtr libraries
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <boost/assign/list_of.hpp> | |
#include <boost/foreach.hpp> | |
#include <boost/function.hpp> | |
#include <boost/phoenix/bind/bind_function_object.hpp> | |
#include <boost/phoenix/core/argument.hpp> | |
#include <boost/phoenix/core/reference.hpp> | |
#include <boost/phoenix/function.hpp> | |
#include <boost/phoenix/object/make_shared.hpp> | |
#include <boost/type_traits/remove_reference.hpp> | |
#include <iostream> | |
#include <map> | |
#include <vector> | |
#include <string> | |
#include <stdexcept> | |
struct parent { virtual std::string hello() const = 0; }; | |
struct child1 : parent { std::string hello() const { return "Hi, child1!"; } }; | |
struct child2 : parent { std::string hello() const { return "Ay, child2!"; } }; | |
struct child3 : parent { | |
std::string name; | |
explicit child3(std::string const & name) : name(name) {} | |
std::string hello() const { return "Howdy, my name is " + name + "."; } | |
}; | |
typedef boost::shared_ptr<parent> parent_ptr; | |
struct get_ { | |
template <typename Sig> struct result; | |
template <typename F, typename M, typename T> | |
struct result<F(M, T)> { | |
typedef | |
typename boost::remove_reference<M>::type::mapped_type const & | |
type; | |
}; | |
template <typename K, typename V, typename T> | |
V const & operator()(std::map<K,V> const & m, T const & x) const { | |
typename std::map<K,V>::const_iterator it = m.find(x); | |
if (it == m.end()) throw std::invalid_argument("No such type!"); | |
return it->second; | |
} | |
}; | |
#if 0 | |
struct call_map_ { | |
template <typename Sig> struct result; | |
template <typename F, typename M, typename T> | |
struct result<F(M, T)> | |
: boost::result_of | |
< typename boost::remove_reference<M>::type::mapped_type() | |
> | |
{}; | |
template <typename K, typename V, typename T> | |
typename boost::result_of<V()>::type | |
operator()(std::map<K,V> const & m, T const & x) const { | |
return get_()(m, x)(); | |
} | |
}; | |
#endif | |
int main() { | |
namespace phx = boost::phoenix; | |
typedef | |
std::map<std::string, boost::function<parent_ptr(void)> > | |
factory_map; | |
factory_map map; | |
map["child1"] = phx::make_shared<child1>(); | |
map["child2"] = phx::make_shared<child2>(); | |
map["billy"] = phx::make_shared<child3>("Billy"); | |
map["jesse"] = phx::make_shared<child3>("Jesse"); | |
typedef boost::function<parent_ptr(std::string const &)> factory; | |
using phx::placeholders::arg1; | |
#if 1 | |
phx::function<get_> get; | |
factory make = phx::bind(get(phx::cref(map), arg1)); | |
#else | |
phx::function<call_map_> call_map; | |
factory make = call_map(phx::cref(map), arg1); | |
#endif | |
try { | |
std::vector<std::string> types = | |
boost::assign::list_of("child1")("child2")("jesse")("billy")("joe"); | |
BOOST_FOREACH(std::string const & type, types) | |
std::cout << make(type)->hello() << std::endl; | |
} catch (std::exception & e) { | |
std::cout << "Error: " << e.what() << std::endl; | |
} | |
// Prints: | |
// Hi, child1! | |
// Ay, child2! | |
// Howdy, my name is Jesse. | |
// Howdy, my name is Billy. | |
// Error: No such class! | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This code (ab)uses Boost.Phoenix further than the previous one, https://gist.github.com/1051564, by implementing most of the factory lookup in Phoenix too.