Simple yet interesting object factory

This is a simple yet interesting object factory. Main points are: - Support for many class hierarchies at the same time - Object constructor arguments with generic type - Object constructor overloading - Support for user supplied 'object create' functions - Dynamic class registering/unregistering - No RTTI or special library requirements, only an associative container is used. - And finally the most important: 100% type safe also at runtime Especially constructor overloading and runtime type safety are two niceties you won't find easily googling around. You can view as HTML page a simple and commented test program here: http://digilander.libero.it/mcostalba/simple_factory/main.cpp.html A page with the source is here: http://digilander.libero.it/mcostalba/simple_factory/simple_factory.hpp.html Below are the links to the actual files: http://digilander.libero.it/mcostalba/simple_factory/main.cpp http://digilander.libero.it/mcostalba/simple_factory/simple_factory.hpp I'm sorry if you find the comments a bit "entry level", but they are intended for a wider audience. Finally there are a couple of bugs that I won't reveal ;-) they are not easy to spot and fixing them will complicate the code. Because this is intended more as a presentation of the ideas then production code I will fix them when I'll be confident design is sound. Anyhow I keep a separated test framework with about 40 tests to exercise the factory under different paths. So I would say this is 'working' code. Any comment or hint on how to improve the design or implementation would be very appreciated. Thanks Marco

On 8/31/07, Janek Kozicki <janek_listy@wp.pl> wrote:
Marco Costalba said: (by the date of Fri, 31 Aug 2007 20:07:37 +0200)
This is a simple yet interesting object factory.
Did you have a look at GSoC extension library? (to be submitted for review)
No, now I check.... ....Ok. I've had a look. Well i won't say "simple", I can get an up to 6 parameter factory with much less KB and copy & paste. Also I've seen factory uses typeid, mine does not uess RTTI. I didn't run the factory, and the tutorial was not enough to say if the factory checks for parameter overloading and checks for ambiguous contructor calls, as example MyClass(int v); MyClass(int& v); MyClass(const int& v); can all be called by new MyClass(7); But compiler errors out (where ctor is called _not_ where ctors are defined!) for ambiguous call. Factory should check against registering this kind of c'tor parameters. Now, very sorry, but I really have to ask you: "Did you have a look at mine?" Thanks Marco

Marco Costalba wrote:
You can view as HTML page a simple and commented test program here: http://digilander.libero.it/mcostalba/simple_factory/main.cpp.html
Your small document doesn't talk about ownership and lifetime management of the created object. As for the forwarding problem, this is solved using rvalue references. However, since they're not available in C++03, people use pass-by-value instead, and boost::ref when they want to pass by reference.

On 9/1/07, Mathias Gaunard <mathias.gaunard@etu.u-bordeaux1.fr> wrote:
Marco Costalba wrote:
You can view as HTML page a simple and commented test program here: http://digilander.libero.it/mcostalba/simple_factory/main.cpp.html
Your small document doesn't talk about ownership and lifetime management of the created object.
The factory returns a plain old pointer to the created object. That's it. You can improve as you want, but I'm more interested in checking the soundness of the design at this stage...there will be time also for smart pointers ;-) but now it's still in "design" time.
As for the forwarding problem, this is solved using rvalue references. However, since they're not available in C++03, people use pass-by-value instead, and boost::ref when they want to pass by reference.
Well, parameters are indeed passed by copy, per default, and by reference only after fully qualifying Factory::object() template parameters. I understand the presentation document it's not very "high quality", it is more "show by examples" stuff. Please refer directly to simple_factory.hpp (it's small enough) to see the details. Thanks Marco

Marco Costalba wrote:
This is a simple yet interesting object factory.
Please see http://tinyurl.com/35vlvb . It seems with that factory utility one could achieve the semantics of your proposal somehow like this (note: untested code for illustration only - see docs and tests): // create a map of functions map< string, function<base_t*(arg1_t,arg2_t)> > f; // register factories f[ "T1" ] = factory<T1>(); // note that this one works too: f[ "T2" ] = bind( factory<T2>(), another_arg, _1, _2); // invoke them base_t* new_t1 = f["T1"](arg1,arg2); base_t* new_t2 = f["T2"](arg1,arg2); It's pretty flexible, isn't it? It also works with smart pointers and there's a variant for by-value construction :-). Regards, Tobias

On 9/1/07, Tobias Schwinger <tschwinger@isonews2.com> wrote:
Marco Costalba wrote:
This is a simple yet interesting object factory.
Please see
. It seems with that factory utility one could achieve the semantics of your proposal somehow like this (note: untested code for illustration only - see docs and tests):
[snip code]
It's pretty flexible, isn't it? It also works with smart pointers and there's a variant for by-value construction :-).
A similar approach could be done with http://dispatcher.sourceforge.net/ -- only this time it's not required that the function registered is a "factory". It could very well be any function registered. base_t * foo(int a, int b) { ... }; // somewhere in code dispatcher<string, base_t*(int, int)> d; d["T1"] = factory<T1>(); d["T2"] = factory<T2>(); d["something else"] = &foo; string input; cin >> input; base_t holder = d[input](1, 2); HTH -- Dean Michael C. Berris http://cplusplus-soup.blogspot.com/ mikhailberis AT gmail DOT com +63 928 7291459

On 9/2/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
On 9/1/07, Tobias Schwinger <tschwinger@isonews2.com> wrote:
Marco Costalba wrote:
This is a simple yet interesting object factory.
Please see
Probably there is a difference in naming conventions between mine and the above proposed link. There "Factory" is actual what in my example is called "Creator", i.e. the _thing_ that calls the object constructor. It is bounded to one object class. While what I called factory, it seems to be called "dispatcher", i.e. a _thing_ that given a key in input, as example a string with the class name, calls the actual object "creator", you would say the object factory. Indeed in the above link I fail to see the mapping framework between class identifiers and actual creators/factories for that class, or put in other words I don't see the dispatcher.
A similar approach could be done with http://dispatcher.sourceforge.net/ -- only this time it's not required that the function registered is a "factory". It could very well be any function registered.
The dispatcher is much nicer ;-) i.e. is what I'm looking for especially for the clean syntax. I will study better. Anyhow dispatcher does not support contructor overloading, as example I can register functions that calls two different object constructors: MyObject* function_0() { return MyObject(); }; MyObject* function_1(int v) { return MyObject(v); }; d["MyObject_0"] = function_0; d["MyObject_1"] = function_1; But when I call I have to use two different keys, in this case "MyObject_0" and "MyObject_1". d["MyObject_0"](); d["MyObject_1"](7); With my example factory I would say instead: Factory::object("MyObject"); // calls function_0 Factory::object("MyObject", 7); // calls function_1 Indeed I didn't find this "constructor overloading" feature in any place. Marco

Marco Costalba wrote:
Indeed in the above link I fail to see the mapping framework between class identifiers and actual creators/factories for that class, or put in other words I don't see the dispatcher.
It's not there, because it's just trivial to implement with what we already have in Boost and the standard library (as shown in the previous post) e.g. using 'std::map' for the mapping and 'boost::function' for the type erasure. See http://www.sgi.com/tech/stl/Map.html http://www.boost.org/doc/html/function.html
A similar approach could be done with http://dispatcher.sourceforge.net/ -- only this time it's not required that the function registered is a "factory". It could very well be any function registered.
Same with the code I posted. The factories are just adapters to make a construction expressions first-class function objects which are then type-erased and stored in 'boost::function's... So it seems a 'dispatcher<Key,Sig>' is pretty much like a 'std::map<Key,boost::function<Sig> >' ;-). Regards, Tobias

Hi Tobias! On 9/2/07, Tobias Schwinger <tschwinger@isonews2.com> wrote:
Same with the code I posted.
The factories are just adapters to make a construction expressions first-class function objects which are then type-erased and stored in 'boost::function's...
So it seems a
'dispatcher<Key,Sig>'
is pretty much like a
'std::map<Key,boost::function<Sig> >'
;-).
Yes, and I would suggest that if the added features of the dispatcher aren't required (like the index validation, routing/message-transformation, exception-friendly functor wrapper, and the invoker interface) then a map would do just fine. Though it is interesting -- I've been playing around with the idea of an overloaded type-safe dispatcher for some time, but I never got to thinking of a way to accomplish it in a clean manner. Basically something that will allow the following: void foo1(int a) { ... }; void foo2(int a, int b) { ... }; dispatcher<signatures<void(int), void(int, int)>, string> d; d["foo"] = &foo1; d["foo"] = &foo2; d["foo"](1); // will call foo1(...) d["foo"](1, 2); // will call foo2(...) d["foo"](1, 2, 3); // will not compile Perhaps it might be doable, even with the current code I already have there but Real Life (TM) and not enough interest (or utility) from the community really bars me from doing much about it. Maybe when Real Life (TM) lets up, I might come around to allowing this. :-) -- Dean Michael C. Berris http://cplusplus-soup.blogspot.com/ mikhailberis AT gmail DOT com +63 928 7291459

On 9/2/07, Dean Michael Berris <mikhailberis@gmail.com> wrote:
Hi Tobias!
On 9/2/07, Tobias Schwinger <tschwinger@isonews2.com> wrote:
Though it is interesting -- I've been playing around with the idea of an overloaded type-safe dispatcher for some time, but I never got to thinking of a way to accomplish it in a clean manner. Basically something that will allow the following:
A possible way, as implemented in my example, is to use a multi-valued map (std::multimap) to store keys so that for each key value you get a set of objects. The second step is to store corresponding signature in the object "as the object type" so that you can check for correct signature with a dynamic_cast<> of stored objects against the dispatch request. Anyhow "simple_factory.hpp" code is much clear then the above explanation... ;-) Marco

Hi Dean, Dean Michael Berris wrote:
Though it is interesting -- I've been playing around with the idea of an overloaded type-safe dispatcher for some time, but I never got to thinking of a way to accomplish it in a clean manner. Basically something that will allow the following:
<code> Seems like a job for 'fusion::map'...
Perhaps it might be doable, even with the current code I already have there but Real Life (TM) and not enough interest (or utility) from the community really bars me from doing much about it. Maybe when Real Life (TM) lets up, I might come around to allowing this.
A very interesting thing related to your work would be to have "Interfaces with Reflection" http://tinyurl.com/58koc (see "Future Directions") . That library is not making any noticeable progress since quite some time now. What is there might still be too complicated at places, but the ideas in it are very hot. I bet you'll get good feedback from the community for bringing something like that up for review... Another thing that you might find interesting: You know the Fusion functional module, don't you? It sorta emulates variadic templates and RValue references in C++98 (where Fusion Sequences are analog to the 'va_list' with C varargs) and allows calling functions / function objects with Tuples for their argument lists. It makes generic callback (and "callforth") facilities very easy to implement, as shown by the cookbook recipe implementing 'bind' in less than 150 LOC and with neither repetitive code nor preprocessor metaprogramming: http://tinyurl.com/ywlhdq . Regards, Tobias

Hi Tobias! On 9/3/07, Tobias Schwinger <tschwinger@isonews2.com> wrote:
Hi Dean,
Dean Michael Berris wrote:
Though it is interesting -- I've been playing around with the idea of an overloaded type-safe dispatcher for some time, but I never got to thinking of a way to accomplish it in a clean manner. Basically something that will allow the following:
<code>
Seems like a job for 'fusion::map'...
Yes, it definitely looks like that to me. Time to brush up on fusion again, seems I have been out of that template metaprogramming world for quite a while now...
Perhaps it might be doable, even with the current code I already have there but Real Life (TM) and not enough interest (or utility) from the community really bars me from doing much about it. Maybe when Real Life (TM) lets up, I might come around to allowing this.
A very interesting thing related to your work would be to have "Interfaces with Reflection"
http://tinyurl.com/58koc (see "Future Directions")
. That library is not making any noticeable progress since quite some time now. What is there might still be too complicated at places, but the ideas in it are very hot. I bet you'll get good feedback from the community for bringing something like that up for review...
This is definitely interesting... I'll try to take a dive in, but basically one thing missing from my current dispatcher implementation is the ability to register functions of different signatures to which a separate type can be "self-registered" to. I'm likening this to something like: struct foo_type { template <class dispatcher_type> explicit foo_type (dispatcher_type & dispatcher_) { dispatcher_["one"] = boost::bind(&foo_type::one, this, _1); dispatcher_["one"] = boost::bind(&foo_type::one, this, _1, _2); }; void one(int) { }; void one(int, int) { }; }; // ... somewhere in main dispatcher< signatures<void(int), void(int, int)>, string > d; foo_type instance(d); find<void(int, int)>(instance)["one"](1, 1); find<void(int)>(instance)["one"](1); There might be a less cryptic way, but that's what I'm looking to implement soon -- which should be pretty close to Interfaces with Reflection. Interesting indeed.
Another thing that you might find interesting: You know the Fusion functional module, don't you?
I can't say I know it very well (yet), but I'm definitely going to go try and look at this really soon.
It sorta emulates variadic templates and RValue references in C++98 (where Fusion Sequences are analog to the 'va_list' with C varargs) and allows calling functions / function objects with Tuples for their argument lists. It makes generic callback (and "callforth") facilities very easy to implement, as shown by the cookbook recipe implementing 'bind' in less than 150 LOC and with neither repetitive code nor preprocessor metaprogramming:
Nice! This is definitely interesting. I'm going to have a hand at "fusion-izing" the dispatcher implementation pretty soon. Thanks for the pointers, I'll definitely look into these. -- Dean Michael C. Berris http://cplusplus-soup.blogspot.com/ mikhailberis AT gmail DOT com +63 928 7291459
participants (5)
-
Dean Michael Berris
-
Janek Kozicki
-
Marco Costalba
-
Mathias Gaunard
-
Tobias Schwinger