Simple object factory: Checking signatures at runtime

I'm extending the 'simple object factory' I have presented to this mailing list few threads ago. It is coming out pretty nice: the number of allowed object c'tor arguments have been extended until a given maximum and instead of an (optional) custom "object creator" function it is now possible to use any callable entity as example a functor object. The factory is now "almost" satisfactory. It has only a couple of drawbacks, one small and a work around does exist. The other is "important" because is a design issue. Very briefly: I can register any c'tor anywhere in a program to teach the factory how to build an object: Factory::register_class<Base, double>("MyObject"); Factory::register_class<Base, int, Base*>("MyObject"); Above instructions automatically instantiate and register two c'tor invokers c1 and c2 defined as: Base* c1(double d) { return new Base(d); } Base* c2(int i, Base* b) { return new Base(i, b); } Constructor overloading support it means that the factory will call two different functions also if the same key "MyObject" is passed depending on the argument types: Base* o1 = Factory::object("MyObject", 3.14); /* function 'c1' is called */ Base* o2 = Factory::object("MyObject", 3, o1); /* function 'c2' is called */ The factory is also able to check the signatures at runtime and discards any wrong call: Base* o3 = Factory::object("MyObject", o1, 3); /* o3 == NULL */ Finally, here it is the current big limitation: automatic argument type conversion is not supported: Factory::object("MyObject", 3.14, o1); /* fails: double -> int is not done */ Derived* d = new Derived(); /* say Derived it's a sub class of Base */ Factory::object("MyObject", 3, d); /* fails: Derived* -> Base* is not done */ The design issue is that type info is templatized so that only "near perfect matches" are discovered. Where "near perfect matches" it means that if a value 'v' has type V and constructor argument accepts type A then we have a match only if: A == V || A == V& || A == const V || A == const V& My question is: there exsist a way to check "relaxed" signatures at run-time? Put in general terms: Given a set 'Set' of functor objects f1,f2,..fn with different signatures in their operator() is it possible to check if a given set of values v1,v2,...vk are compatible with one or more of them ? What I would need is an implementation of the following algorithm: foreach(f in Set) if ( "f(v1,v2,..,vk)" is compilable ) return f; Constrains are: - Functors can be "registered" with the factory in different times and in different translation units. - At runtime you have a only set of values as input: v1,..vk - Functor signatures may not be homogeneous Thanks for your help Marco

On 9/6/07, Mathias Gaunard <mathias.gaunard@etu.u-bordeaux1.fr> wrote:
Marco Costalba wrote:
What I would need is an implementation of the following algorithm:
foreach(f in Set) if ( "f(v1,v2,..,vk)" is compilable ) return f;
function_traits, SFINAE, and verbose meta-programming.
This would work if you were using something like Boost.Fusion in the background where most of the processing is done at compile time. However I believe the OP was looking for a solution at runtime, which pretty hard to achieve if you're going to rely on RTTI. I'm looking for a similar solution, but more towards improving http://dispatcher.sourceforge.net/ to be able to support multiple function signatures in a single dispatcher instance. I think I've got a way to accomplish that with Boost.Fusion, but I doubt this same approach you propose will work for runtime determination. Unless I'm missing something, in which case please enlighten me. Thanks! -- Dean Michael C. Berris http://cplusplus-soup.blogspot.com/ mikhailberis AT gmail DOT com +63 928 7291459

On 9/6/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
On 9/6/07, Mathias Gaunard <mathias.gaunard@etu.u-bordeaux1.fr> wrote:
Marco Costalba wrote:
What I would need is an implementation of the following algorithm:
foreach(f in Set) if ( "f(v1,v2,..,vk)" is compilable ) return f;
function_traits, SFINAE, and verbose meta-programming.
This would work if you were using something like Boost.Fusion in the background where most of the processing is done at compile time. However I believe the OP was looking for a solution at runtime, which pretty hard to achieve if you're going to rely on RTTI.
Yes. Correct. At compile time it's not a problem, also is not a problem to check for the same signature parameter types at runtime. The real problem is to support automatic conversions (int -> double, derived* -> base*) at runtime.
I'm looking for a similar solution, but more towards improving http://dispatcher.sourceforge.net/ to be able to support multiple function signatures in a single dispatcher instance. I think I've got a way to accomplish that with Boost.Fusion, but I doubt this same approach you propose will work for runtime determination.
Unless I'm missing something, in which case please enlighten me.
I studied your dispatcher code. The "trick" is that it supports only one signature per dispatcher. So that all the objects stored your maps could be easily derived form a base class with a given and fixed signature. When you want to store objects with different signatures in a single map you need (or at least I was not able to find something better ;-) to use a common base class with no signature information (StorableClass) and store pointers of that class, then you add signature info subclassing that class with a class templetized on a given signature (SignatureClass). So you have a possible map: map[(key1,p1) (key2,p2) (key3,p3) .... ] where pointers StorableClass *p1, *p2, *p3 are indeed pointers to objects of 3 different instances of a template<>SignatureClass So pointers can coexist together also if the objects they point have different signatures. In the "simple_factory.hpp" example, I posted in a previous thread, a dynamic_cast at runtime is used to check the signatures hidden behind p1,p2,p3 against a given one. The real problem is that two SignatureClass objects with different signatures: SignatureClass<int (int,int)> and SignatureClass<int (int,double)> HAVE DIFFERENT TYPE!!! so that a dynamic_cast is unable to discover that a set of values v1,v2 that could be used for the first one can be feed also to the second one. Hope is clear...at least a bit ;-) Thanks Marco

Hi Marco, On 9/6/07, Marco Costalba <mcostalba@gmail.com> wrote:
On 9/6/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
I'm looking for a similar solution, but more towards improving http://dispatcher.sourceforge.net/ to be able to support multiple function signatures in a single dispatcher instance. I think I've got a way to accomplish that with Boost.Fusion, but I doubt this same approach you propose will work for runtime determination.
Unless I'm missing something, in which case please enlighten me.
I studied your dispatcher code. The "trick" is that it supports only one signature per dispatcher. So that all the objects stored your maps could be easily derived form a base class with a given and fixed signature.
This is by design to enable coherent code which in place of a switch() {...} allows you to dispatch functions which are registered during runtime instead of just being statically defined at compile time. Consider how Boost.Signals does it by making it simple to have a homogeneous container of functions that got signalled when a message is passed to it -- only Boost.Signals is an excellent implementation of the publish-subscribe channel pattern, whereas the dispatcher is meant to be an implementation of a message router pattern.
When you want to store objects with different signatures in a single map you need (or at least I was not able to find something better ;-) to use a common base class with no signature information (StorableClass) and store pointers of that class, then you add signature info subclassing that class with a class templetized on a given signature (SignatureClass).
So you have a possible map:
map[(key1,p1) (key2,p2) (key3,p3) .... ]
where pointers
StorableClass *p1, *p2, *p3 are indeed pointers to objects of 3 different instances of a template<>SignatureClass
So pointers can coexist together also if the objects they point have different signatures. In the "simple_factory.hpp" example, I posted in a previous thread, a dynamic_cast at runtime is used to check the signatures hidden behind p1,p2,p3 against a given one.
The real problem is that two SignatureClass objects with different signatures:
SignatureClass<int (int,int)> and SignatureClass<int (int,double)>
HAVE DIFFERENT TYPE!!! so that a dynamic_cast is unable to discover that a set of values v1,v2 that could be used for the first one can be feed also to the second one.
Hope is clear...at least a bit ;-)
In this case, I think the approach I will take will be a bit more different that what you have chosen to do. Since I plan to do something like: void foo(int a) { ... }; void bar(int a, int b) { ... }; void foobar(int a, double b) { ... }; dispatcher< fusion::vector<void(int), void(int,int), void(int, double)> > d; d[0] = &foo; d[0] = &bar; d[0] = &foobar; If you look at the implementation(s) for the "functor" type in the dispatcher, it would be possible for it to provide the three operator() overloads following signatures given as a fusion::vector<> by containing three boost::function<>'s each having one signature, and having the deduction done during compile-time still. So that means: d[0](1); // foo() is called d[0](1, 2); // bar() is called d[0](1, 2.1); // foobar() is called This will be possible since the dispatcher's operator[] will return a reference to a 'functor' instance which overloads operator() following the many signatures it is configured to support. I think Boost.Fusion will definitely help in this extension through the fold<> algorithm/metafunction (for linear inheritance for the signature overloads). Although I'm not a Boost.Fusion expert, I'm pretty confident it's just a matter of sitting down and actually getting things to work the way I want them to work. I'm also right now (at least initially) convinced that this is actually feasible. ;) -- Dean Michael C. Berris http://cplusplus-soup.blogspot.com/ mikhailberis AT gmail DOT com +63 928 7291459

On 9/6/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
is passed to it -- only Boost.Signals is an excellent implementation of the publish-subscribe channel pattern, whereas the dispatcher is meant to be an implementation of a message router pattern.
Thanks for your hint, I will study Boost.Signals then.
void foo(int a) { ... }; void bar(int a, int b) { ... }; void foobar(int a, double b) { ... };
dispatcher< fusion::vector<void(int), void(int,int), void(int, double)> > d; d[0] = &foo; d[0] = &bar; d[0] = &foobar;
If you look at the implementation(s) for the "functor" type in the dispatcher, it would be possible for it to provide the three operator() overloads following signatures given as a fusion::vector<> by containing three boost::function<>'s each having one signature, and having the deduction done during compile-time still. So that means:
d[0](1); // foo() is called d[0](1, 2); // bar() is called d[0](1, 2.1); // foobar() is called
More or less I can achieve this also with my very simple and raw implementation, what I cannot achieve is something like this: void foobar3(int a, double b, double c) { ... }; void foobar4(int a, double b, std::string) { ... }; d[0] = &foobar3; d[0] = &foobar4; d[0](1, 1, 1); // foobar3() is called d[0](1, 2.4, "Test"); // foobar4() is called Is this possible using fusion::vector<> ?
I think Boost.Fusion will definitely help in this extension through the fold<> algorithm/metafunction (for linear inheritance for the signature overloads).
Boost.Fusion is another place where I'm going to look :-) thanks. Marco

Hi Marco, On 9/6/07, Marco Costalba <mcostalba@gmail.com> wrote:
If you look at the implementation(s) for the "functor" type in the dispatcher, it would be possible for it to provide the three operator() overloads following signatures given as a fusion::vector<> by containing three boost::function<>'s each having one signature, and having the deduction done during compile-time still. So that means:
d[0](1); // foo() is called d[0](1, 2); // bar() is called d[0](1, 2.1); // foobar() is called
More or less I can achieve this also with my very simple and raw implementation, what I cannot achieve is something like this:
void foobar3(int a, double b, double c) { ... }; void foobar4(int a, double b, std::string) { ... };
d[0] = &foobar3; d[0] = &foobar4;
d[0](1, 1, 1); // foobar3() is called
d[0](1, 2.4, "Test"); // foobar4() is called
Is this possible using fusion::vector<> ?
The intended use of fusion::vector<> is to become a compile-time container (think of mpl::vector<>) of the function prototypes/signatures which the 'functor' wrapper should implement/support. At the same time, a fusion::vector<> can map a numeric index to a runtime instance (ala tuple) of the type defined in the indexed element of the vector. In code, that looks like: fusion::vector<int, double, string> a(1, 2.1, "1"); int i = get<0>(a); // 1 at compile time double d = get<1>(a); // 2.1 at compile time string s = get<2>(a); // "1" at compile time Though I'm pretty sure I'm not doing Boost.Fusion docs justice by my above description, I think it would be better if you checked it out for yourself. ;)
I think Boost.Fusion will definitely help in this extension through the fold<> algorithm/metafunction (for linear inheritance for the signature overloads).
Boost.Fusion is another place where I'm going to look :-) thanks.
I definitely hope you find Boost.Fusion useful as well -- it's already been useful in my work, and I'm thankful there's something like this that has come along. -- Dean Michael C. Berris http://cplusplus-soup.blogspot.com/ mikhailberis AT gmail DOT com +63 928 7291459

On 9/6/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
In this case, I think the approach I will take will be a bit more different that what you have chosen to do. Since I plan to do something like:
void foo(int a) { ... }; void bar(int a, int b) { ... }; void foobar(int a, double b) { ... };
dispatcher< fusion::vector<void(int), void(int,int), void(int, double)> > d;
That's another design decision is not suitable for an object factory. When you instantiate the dispatcher you already know _all_ the signatures that the dispacther will provide. But for a factory this is not true. You can register/add new signatures at runtime anywhere in the program. It would be if you dispacther is able to support something like this: dispatcher< fusion::vector<void(int), void(int,int), void(int, double)> > d; double another_foo(char*) { ... }; d += fusion::vector<double(char*)>; d[0] = &another_foo; d[0]("test"); // another_foo() is called Marco

On 9/6/07, Marco Costalba <mcostalba@gmail.com> wrote:
On 9/6/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
dispatcher< fusion::vector<void(int), void(int,int), void(int, double)> > d;
That's another design decision is not suitable for an object factory.
I'm not sure I follow you here...
When you instantiate the dispatcher you already know _all_ the signatures that the dispacther will provide.
But for a factory this is not true. You can register/add new signatures at runtime anywhere in the program.
I guess this would be true for languages like Python where you have introspection and reflection built in -- allowing you to query the type and see what available functions/methods are there and register those during runtime, because it's inherently dynamic (the language).
It would be if you dispacther is able to support something like this:
dispatcher< fusion::vector<void(int), void(int,int), void(int, double)> > d;
double another_foo(char*) { ... };
d += fusion::vector<double(char*)>;
d[0] = &another_foo;
d[0]("test"); // another_foo() is called
I guess the problem the dispatcher is meant to solve is way different from what your object factory is meant to address. However, something like this comes to mind (assuming that the functionality of multiple signatures is already in the dispatcher): struct my_type { typedef dispatcher<fusion::vector<my_type*(int), my_type*(int, int)>, std::string > registry; static my_type * create_1(int i) { return new my_type(i); }; static my_type * create_2(int i, int j) { return new my_type(i, j); }; static void init(registry & registry_) { registry_["my_type"] = &my_type::create_1; registry_["my_type"] = &my_type::create_2; }; // rest of implementation of the type, including // constructors, methods, etc. } template <class T> struct factory { typename T::registry registry; factory_base() { T::init(registry); }; typedef typename T::registry::functor_type return_type; return_type & operator[] (typename t::registry::index_type index) { return registry[index]; }; } // ... factory<my_type> my_factory; my_type * ptr = my_factory["my_type"](1, 1); In this approach, the factory is type specific and the initialization of the factory falls on the actual type to be registered in the factory -- and is enforced at compile-time leading to less bugs that will reach runtime. I guess my reluctance to provide flexibility at runtime will limit the implementation of the dispatcher, which is intended to be as type-safe and static as much as possible -- whereas a goal of your object factory is to be flexible at runtime, which I don't see adds much value especially to the factory pattern because you'll need to know the types at compile-time anyway. I see that at this point our implementations will begin to diverge because the goals of our libraries are considerably different. I don't mind this one bit at all though. :) Don't let that stop you from working on your object factory. :) -- Dean Michael C. Berris http://cplusplus-soup.blogspot.com/ mikhailberis AT gmail DOT com +63 928 7291459

On 9/7/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
I guess the problem the dispatcher is meant to solve is way different from what your object factory is meant to address. However, something like this comes to mind (assuming that the functionality of multiple signatures is already in the dispatcher):
struct my_type { typedef dispatcher<fusion::vector<my_type*(int), my_type*(int, int)>, std::string > registry;
Why fixed argument type 'int' ? -----cut -----
// ... factory<my_type> my_factory; my_type * ptr = my_factory["my_type"](1, 1);
In this approach, the factory is type specific and the initialization of the factory falls on the actual type to be registered in the factory -- and is enforced at compile-time leading to less bugs that will reach runtime.
It's ok to be type specific, actually I have a factory for each base class, as example Factory<Base> will be able to create all the objects derived from Base while Factory<Base2> is needed to create objects derived from Base2. So type specific on the return type is not an issue because of dynamic polimorfism allows user to up cast to needed type: Base* p = Factory<Base>::get_object("Derived"); Derived* d = dynamic_cast<Derived*>(p); // perhaps not nice but it works...
I guess my reluctance to provide flexibility at runtime will limit the implementation of the dispatcher, which is intended to be as type-safe and static as much as possible -- whereas a goal of your object factory is to be flexible at runtime, which I don't see adds much value especially to the factory pattern because you'll need to know the types at compile-time anyway.
Well, you could have classes defined in different transaltion units, or in different libraries written by different authors in different times. As example a library vendor could provide an object factory for their classes togheter with the library. Then a library user could register with the same factory the classes he writes subclussing the vendor's ones. The object vendor factory does not know anything about the users ones and the only and sufficient constrain is that the user classes are derived from a base class on which the factory is instantiated.
I see that at this point our implementations will begin to diverge because the goals of our libraries are considerably different.
I'm not able to see so far ;-) I will try to follow your developments... Thanks Marco

Hi Marco, On 9/7/07, Marco Costalba <mcostalba@gmail.com> wrote:
On 9/7/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
I guess the problem the dispatcher is meant to solve is way different from what your object factory is meant to address. However, something like this comes to mind (assuming that the functionality of multiple signatures is already in the dispatcher):
struct my_type { typedef dispatcher<fusion::vector<my_type*(int), my_type*(int, int)>, std::string > registry;
Why fixed argument type 'int' ?
This is for example purposes only.
-----cut -----
// ... factory<my_type> my_factory; my_type * ptr = my_factory["my_type"](1, 1);
In this approach, the factory is type specific and the initialization of the factory falls on the actual type to be registered in the factory -- and is enforced at compile-time leading to less bugs that will reach runtime.
It's ok to be type specific, actually I have a factory for each base class, as example
Factory<Base> will be able to create all the objects derived from Base while Factory<Base2> is needed to create objects derived from Base2.
So type specific on the return type is not an issue because of dynamic polimorfism allows user to up cast to needed type:
Base* p = Factory<Base>::get_object("Derived");
Derived* d = dynamic_cast<Derived*>(p); // perhaps not nice but it works...
Hmmm... I personally don't see why you'd want to cast down to a derived type when you already have a reference to the base type -- or why you'd want a reference from a base type when you really want a reference to a specific type. Yes, it's possible and allowed by the language but the utility (and logic) of this doesn't appeal to me personally.
I guess my reluctance to provide flexibility at runtime will limit the implementation of the dispatcher, which is intended to be as type-safe and static as much as possible -- whereas a goal of your object factory is to be flexible at runtime, which I don't see adds much value especially to the factory pattern because you'll need to know the types at compile-time anyway.
Well, you could have classes defined in different transaltion units, or in different libraries written by different authors in different times.
But how do these types register themselves to the "factory"? Wouldn't they (the derived types) need to know about the factory in the first place to register themselves? Or would external code have to do this -- but in which case why not just have the construction handlers mapped to an std::map<> and be done with it, or since any other kludge would be too involved, why not just custom Factories?
As example a library vendor could provide an object factory for their classes togheter with the library. Then a library user could register with the same factory the classes he writes subclussing the vendor's ones.
The object vendor factory does not know anything about the users ones and the only and sufficient constrain is that the user classes are derived from a base class on which the factory is instantiated.
So how different is this approach from using the dispatcher separate from all the libraries and just gluing them together for a custom "factory registry"?
I see that at this point our implementations will begin to diverge because the goals of our libraries are considerably different.
I'm not able to see so far ;-) I will try to follow your developments...
I think the divergence comes from my focus on static polymorphic implementations, while you would like to make runtime-polymorphic support the focus. Unless I'm wrong, in which I'd be glad to be enlightened. :)
Thanks Marco
Thanks for taking the time too. I'll try to follow your developments as well. I might pick up a few tricks as well for the dispatcher. ;-) -- Dean Michael C. Berris http://cplusplus-soup.blogspot.com/ mikhailberis AT gmail DOT com +63 928 7291459

On 9/8/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
So type specific on the return type is not an issue because of dynamic polimorfism allows user to up cast to needed type:
Base* p = Factory<Base>::get_object("Derived");
Derived* d = dynamic_cast<Derived*>(p); // perhaps not nice but it works...
Hmmm... I personally don't see why you'd want to cast down to a derived type when you already have a reference to the base type
p->derivedOnlyMethod(); // compile ERROR! d->derivedOnlyMethod(); // OK
why you'd want a reference from a base type when you really want a reference to a specific type.
This is a Factory impelmentation limitation indeed the outher shell of factory object creation function, the one that the user calls to get an object: Factory<Base>::object() currently retirieves the correct invoker/creator from the map and forwards the calling arguments. The problem is this wrapper is instantiated with the factory, so can only return a pointer of Base* type because it is the only class he knows _when_ it is instantiated. This is due to deferred class registering feature. Only knowing all the classes that the factory will produce at the moment the factory is instantiated could fix this issue IMHO. In case of dispatcher you have only one return type for all the functions you handle, also if with different signatures. If you relax the constarin, as it is foreseeble, to allow covariant return types for pointers to polimorfic objects, perhaps you will found the same issue.
As example a library vendor could provide an object factory for their classes togheter with the library. Then a library user could register with the same factory the classes he writes subclussing the vendor's ones.
The object vendor factory does not know anything about the users ones and the only and sufficient constrain is that the user classes are derived from a base class on which the factory is instantiated.
So how different is this approach from using the dispatcher separate from all the libraries and just gluing them together for a custom "factory registry"?
Currently the dipatcher has the following design decisions that impact a possible use as an object factory: - Single signature function: already planned to be relaxed. - Single return type: forces a factory to produce one kind of objects - Signature list registration at dispatcher instantation: this forces the user to know in advance all the signatures she will use at the point of dispatcher instantation. I don't have the foresight to know if can impact a library/user code scenario but for sure It's a strong request.
I think the divergence comes from my focus on static polymorphic implementations, while you would like to make runtime-polymorphic support the focus. Unless I'm wrong, in which I'd be glad to be enlightened. :)
Yes, I think the same, but I also think that having a good static polymorphic implementation is a very valuable base from which to adventure in the runtime world ;-) Marco

Hi Marco! On 9/8/07, Marco Costalba <mcostalba@gmail.com> wrote:
On 9/8/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
Hmmm... I personally don't see why you'd want to cast down to a derived type when you already have a reference to the base type
p->derivedOnlyMethod(); // compile ERROR! d->derivedOnlyMethod(); // OK
Yes, but I meant it in a higher level of design -- why you would want to refer to an object instance through a reference to the base type and *then* cast it to a derived type.
why you'd want a reference from a base type when you really want a reference to a specific type.
This is a Factory impelmentation limitation indeed the outher shell of factory object creation function, the one that the user calls to get an object: Factory<Base>::object() currently retirieves the correct invoker/creator from the map and forwards the calling arguments.
The problem is this wrapper is instantiated with the factory, so can only return a pointer of Base* type because it is the only class he knows _when_ it is instantiated. This is due to deferred class registering feature.
Only knowing all the classes that the factory will produce at the moment the factory is instantiated could fix this issue IMHO.
Which actually makes sense, to the effect of: factory_pool<fusion::vector<base1_t, base2_t, base3_t> > pool; base2_t * ptr = typename pool::template factory<base2_t>::object();
In case of dispatcher you have only one return type for all the functions you handle, also if with different signatures. If you relax the constarin, as it is foreseeble, to allow covariant return types for pointers to polimorfic objects, perhaps you will found the same issue.
I'll look into the feasibility of different return types. Off the top of my head, I'm thinking this should be possible, though would usually be a bit more tricky than my initial assessment of the problem and possible implementation(s). This is a good idea though, having different signatures having different return types... :)
So how different is this approach from using the dispatcher separate from all the libraries and just gluing them together for a custom "factory registry"?
Currently the dipatcher has the following design decisions that impact a possible use as an object factory:
- Single signature function: already planned to be relaxed.
Yes, I should get to doing this pretty soon -- because I see a pretty big use-case for this requirement in the current (professional) project I'm working on.
- Single return type: forces a factory to produce one kind of objects
I will explore allowing multiple return types definitely.
- Signature list registration at dispatcher instantation: this forces the user to know in advance all the signatures she will use at the point of dispatcher instantation. I don't have the foresight to know if can impact a library/user code scenario but for sure It's a strong request.
Because of the focus on type-safety, I don't think there's any way the dispatcher can support many other signatures without having them explicitly listed during a dispatcher's instantiation. If there was a way to modify a type during runtime, then perhaps that'd be the day -- but since C++ remains statically typed and both statically/dynamically polymorphic then I'll stick to having the types listed down at compile time at type instantiation and prefer statically polymorphic rather than dynamic polymorphic implementations. So it will remain more or less: dispatcher<fusion::set<void(int), void(double), void(std::string)> > d;
I think the divergence comes from my focus on static polymorphic implementations, while you would like to make runtime-polymorphic support the focus. Unless I'm wrong, in which I'd be glad to be enlightened. :)
Yes, I think the same, but I also think that having a good static polymorphic implementation is a very valuable base from which to adventure in the runtime world ;-)
Indeed. :) -- Dean Michael C. Berris http://cplusplus-soup.blogspot.com/ mikhailberis AT gmail DOT com +63 928 7291459

On 9/6/07, Marco Costalba <mcostalba@gmail.com> wrote:
On 9/6/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
dispatcher< fusion::vector<void(int), void(int,int), void(int, double)> > d;
That's another design decision is not suitable for an object factory.
I'm not sure I follow you here...
When you instantiate the dispatcher you already know _all_ the signatures that the dispacther will provide.
But for a factory this is not true. You can register/add new signatures at runtime anywhere in the program.
I guess this would be true for languages like Python where you have introspection and reflection built in -- allowing you to query the type and see what available functions/methods are there and register those during runtime, because it's inherently dynamic (the language).
It would be if you dispacther is able to support something like this:
dispatcher< fusion::vector<void(int), void(int,int), void(int, double)> > d;
double another_foo(char*) { ... };
d += fusion::vector<double(char*)>;
d[0] = &another_foo;
d[0]("test"); // another_foo() is called
I guess the problem the dispatcher is meant to solve is way different from what your object factory is meant to address. However, something like this comes to mind (assuming that the functionality of multiple signatures is already in the dispatcher): struct my_type { typedef dispatcher<fusion::vector<my_type*(int), my_type*(int, int)>, std::string > registry; static my_type * create_1(int i) { return new my_type(i); }; static my_type * create_2(int i, int j) { return new my_type(i, j); }; static void init(registry & registry_) { registry_["my_type"] = &my_type::create_1; registry_["my_type"] = &my_type::create_2; }; // rest of implementation of the type, including // constructors, methods, etc. } template <class T> struct factory { typename T::registry registry; factory_base() { T::init(registry); }; typedef typename T::registry::functor_type return_type; return_type & operator[] (typename t::registry::index_type index) { return registry[index]; }; } // ... factory<my_type> my_factory; my_type * ptr = my_factory["my_type"](1, 1); In this approach, the factory is type specific and the initialization of the factory falls on the actual type to be registered in the factory -- and is enforced at compile-time leading to less bugs that will reach runtime. I guess my reluctance to provide flexibility at runtime will limit the implementation of the dispatcher, which is intended to be as type-safe and static as much as possible -- whereas a goal of your object factory is to be flexible at runtime, which I don't see adds much value especially to the factory pattern because you'll need to know the types at compile-time anyway. I see that at this point our implementations will begin to diverge because the goals of our libraries are considerably different. I don't mind this one bit at all though. :) Don't let that stop you from working on your object factory. :) -- Dean Michael C. Berris http://cplusplus-soup.blogspot.com/ mikhailberis AT gmail DOT com +63 928 7291459

AMDG Marco Costalba <mcostalba <at> gmail.com> writes:
At compile time it's not a problem, also is not a problem to check for the same signature parameter types at runtime.
The real problem is to support automatic conversions (int -> double, derived* -> base*) at runtime.
I would try this struct implicit_conversion { const std::type_info* from_type; const std::type_info* to_type; void* (convert)(void*); void (*destroy)(void*); } class implicit_conversion_set { std::set<implicit_conversion> conversions; }; template<class R> class dispatcher { implicit_conversion_set conversions; R (*f0)(); std::map<tuple<const std::type_info*>, R(*)(void*)> f1; std::map<tuple<const std::type_info*, const std::type_info*>, R(*)(void*, void*)> f2; //... }; i.e. implicit conversions need to be registered. In Christ, Steven Watanabe
participants (4)
-
Dean Michael Berris
-
Marco Costalba
-
Mathias Gaunard
-
Steven Watanabe