dariomt@gmail.com wrote:
class Base {...};
class Factory {...};
template <typename T> struct Helper {...}; // constructor registers
creation function for template parameter
Now we have a template defining a family of derived classes:
template class DerivedUVW : public
Base {...};
...
And all possible U V and W classes in the combination game:
struct A1 {}; struct A2 {}; // for U
struct B1 {}; struct B2 {}; // for V
struct C1 {}; struct C2 {}; // for W
...
And now the six million dollar question:
Is there a way in which MPL and fusion can automatically do the
registration?
I think so (see attachment)!
Here's an MPL-based solution. It does not require any preprocessor code
and compiles with GCC4.
Just for the fun of it, I reduced the Factory code to a one-liner using
the recently reviewed factory functional, which can be downloaded here:
http://tinyurl.com/35vlvb
Regards,
Tobias
#include <iostream>
#include <sstream>
#include <string>
#include <memory>
#include <map>
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// Class hierarchy:
class base
{
public:
virtual void introduce_yourself() = 0;
virtual ~base() { }
};
template< class U, class V, class W >
class derived : public base
{
public:
static std::string name()
{
// not using typeid(derived).name() since ABI-dependent
static std::string* result;
if (! result)
{
std::ostringstream s;
s << "derived<" << U::name() << "," << V::name()
<< "," << W::name() << ">";
result = new std::string(s.str());
}
return *result;
}
void introduce_yourself()
{
std::cout << "Hi I'm " << name() << "." << std::endl;
}
};
// Arguments for 'derived' (note I could've used some traits class
// for the names):
struct A1
{
static char const* name() { return "A1"; }
};
struct A2
{
static char const* name() { return "A2"; }
};
struct B1
{
static char const* name() { return "B1"; }
};
struct B2
{
static char const* name() { return "B2"; }
};
struct C1
{
static char const* name() { return "C1"; }
};
struct C2
{
static char const* name() { return "C2"; }
};
// Factory pattern reduced to its essence, using the recently reviewed
// function object:
std::map< std::string, boost::function > factories;
// Metaprogramming
namespace mpl = boost::mpl;
using namespace mpl::placeholders;
// Let's call an iterator and a range a "cursor"
template< class Iter, class From, class To > struct cursor;
// We create it from a sequence...
template< class Sequence >
struct make_cursor
{
typedef typename mpl::begin<Sequence>::type from;
typedef typename mpl::end<Sequence>::type to;
typedef cursor type;
};
// ...can dereference it...
template< class Cursor > struct deref;
template< class Iterator, class From, class To >
struct deref< cursor >
: mpl::deref<Iterator>
{ };
// ...move it forward...
template< class Cursor > struct next;
template< class Iterator, class From, class To >
struct next< cursor >
{
typedef cursor< typename mpl::next<Iterator>::type, From, To > type;
};
// ...and have it wrap around once it reaces the end.
template< class Cursor > struct wrap_around;
template< class Iterator, class From, class To >
struct wrap_around< cursor >
{
typedef cursor type;
typedef mpl::false_ wrapped;
};
template< class To, class From >
struct wrap_around< cursor >
{
typedef cursor type;
typedef mpl::true_ wrapped;
};
// State machine intended to be used with mpl::fold that adds moved cursors to
// a sequence until one does not hit the end. Remaining cursors are added as-is.
struct nested_loops_fold_op
{
typedef mpl::pair< mpl::true_, mpl::vector<> > initial_state;
template< class State, class Cursor >
struct apply;
template< class Sequence, class Cursor >
struct apply< mpl::pairmpl::true_,Sequence, Cursor >
{
typedef typename next<Cursor>::type next_cursor;
typedef typename wrap_around::type new_cursor;
typedef typename wrap_around::wrapped wrapped;
typedef typename mpl::push_back::type sequence;
typedef mpl::pair< wrapped, sequence > type;
};
template< class Sequence, class Cursor >
struct apply< mpl::pairmpl::false_,Sequence, Cursor >
{
typedef typename mpl::push_back::type sequence;
typedef mpl::pair< mpl::false_, sequence > type;
};
};
template< class Cursors, class Done >
struct register_factories_impl
{
static inline void call()
{
// deref cursors and specialize 'derived' template
typedef typename mpl::unpack_args< derived<_1,_2,_3> >
// typedef typename xyz
::template apply<
mpl::transform_view< Cursors, deref<_1> >
>::type the_type;
// register factory
factories[the_type::name()] = boost::factory< std::auto_ptr >();
// tail-recurse
typedef typename mpl::fold::type next_state;
register_factories_impl<
typename mpl::second::type,
typename mpl::first::type >::call();
}
};
template< class Cursors >
struct register_factories_impl< Cursors, mpl::true_ >
{
static inline void call()
{ }
};
template< class Sequences >
inline void register_factories()
{
typedef typename mpl::transform >::type cursors;
typedef typename mpl::fold::type next_state;
typedef typename mpl::first::type done;
register_factories_impl::call();
}
int main()
{
register_factories<
mpl::vector<
mpl::vector,
mpl::vector,
mpl::vector
>
>();
factories["derived"]()->introduce_yourself();
factories["derived"]()->introduce_yourself();
// ...
return 0;
}