Skip to content

Instantly share code, notes, and snippets.

@pyrtsa
Created June 29, 2011 19:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pyrtsa/1054616 to your computer and use it in GitHub Desktop.
Save pyrtsa/1054616 to your computer and use it in GitHub Desktop.
Object factory v2, using Boost.Phoenix, Boost.Function and Boost.SmartPtr libraries
#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!
}
@pyrtsa
Copy link
Author

pyrtsa commented Jun 29, 2011

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment