Boost logo

Boost :

From: Vladimir Prus (ghost_at_[hidden])
Date: 2004-12-06 04:38:25


Roland Schwarz wrote:

>>What if I write:
>>
>> shape* ps2 = dynamic_new<shape>("circle", 20);
>>
>>?
>>
> Since I am using a template function as a type generator and
> tipeid().name() in turn
> this will deduce a function requiring an int for the ctor. Since only
> double has been
> registered in the example program your example will not work. (It will
> give a 0 -pointer
> at runtime.)

Yes, that's what I though. In other words, your implementation is
dynamically checked. (This is consistent with the name 'dynamic_new', BTW).

> Please note that my implementation is not very smart and could be
> improved by someone
> more knowledgeable than me. Perhaps it is not so hard to add support for
> automatic
> type conversion too?

The problem is that need either:
1. A statically available list of overloaded functions, so that compiler can
do the overload resolution.
2. Boost.Overload library which can do it using typeid or some other
metedata. Such library does not exist, though :-(

> But then my implementation fits entirely (almost) on two sheets of paper.

Mine too ;-)

    template<class BasePlugin>
    struct virtual_constructors {
        typedef mpl::list<mpl::list<> > type;
    };

> Altough I have not a very good knowledge of the mpl lib right now, this
> looks
> very interseting to me.
>
>> The disadvantage is that you need to
>>explicitly instantiate 'virtual_construct',
>>
> Hmm, I cannot see how I ever could do away with this instatiation. Or do
> you mean it should better be done implicitely?

Well, I mean that unlike your solution, you can query for specific
constructor signature. Using plugins as example, even if specific plugin
class has additional constructors, it's not possible to call them via
generic interface.

>> but then you get static
>>checking. For example, a plugin can't forget to define a required
>>constructor.
>>
>>I also considered this syntax:
>> struct virtual_constructors<Weapon> {
>> typedef mpl::list<ctor (std::string),
>> ctor (std::string, int)> .....
>>
>>where 'ctor' is auxillary struct, but maybe it's too smart, haven't
>>decided yet.
>>
>>
> I am not entirely sure, if you intend this struct as external to your
> class or as a
> member?

External template that the user has to specialize.

> Most likely I did not yet get the full picture and my question
> might seem
> somewhat blurry. Could you post a little example that exhibits the user
> interface?

Sure. I'll expand the previous example.

You have a class which is intended to be "base" for plugins. So, you can
load dynamic library, and ask it to create a class, giving name (string)
and a set of parameter. You can back a pointer to "base". Here's definition
of the base class:

   class Weapon {
   public:
      virtual void fire() = 0;
      virtual ~Weapon() {}
   };

Second, it's needed to define a set of constructor parameter that each
plugin should support:

  namespace boost { namespace plugin {
  template<>
  struct virtual_constructors<Weapon> {
      typedef mpl::list<mpl::list<std::string>,
                        mpl::list<std::string, int>
> type;
  };

The machinery used to create plugins is somewhat complex. I can describe the
logic used for plugins, but to save space will describe only part which is
usable everywhere. A class can be registred with:

  std::map<std::string, boost::any> classes;
  static boost::plugin::concrete_factory<Weapon, Missile> cf;
  boost::plugin::abstract_factory<Weapon>* w = &cf;
  classes.insert(std::make_pair("missile", w));

The 'abstract_factory' has a virtual 'create' method for each signature
declared by 'virtual_constructors'. The 'concrete_factory' class defines
those methods for a specific class to be created.

The above map can be used as:

  // Want to create a weapon by name
  std::any f = classes["missile"];
  any_cast<abstract_factory<Weapon>* >(f)->create("foo", 10);

The use of any allows to store completely different factories in one map,
and any_cast will verify that you're using the correct type.

In Boost.Plugins the above code is hidden under higher-level interface,
like:

  BOOST_EXPORT_PLUGIN(Weapon, Missile, "Missile");
  BOOST_EXPORT_PLUGIN_LIST();

but it's just for convenience.

- Volodya


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk