It's been a while since the last update, so I've gathered up a few bug fixes and feature additions for the factory library, now ready to be unleashed upon an unsuspecting world.
Non-exhaustive list of changes:
- Fixed SFINAE bug that only manifested itself (quite correctly, I might add) on ICC, thus not being discovered earlier. Library now compiles successfully on ICC 11.1
- Reworked concrete creators to use a member type tagging system rather than the old, somewhat dodgy template specialization system (this is primarily an implementation detail)
- Added ability to access stored creator map in factory class
- Ensured backwards compatibility beyond Boost 1.42 due to certain Fusion changes
- Made directory structure more in line with Boost libraries
- Moved to Boost.Build for building and running unit tests
- Minor doc updates and additions, but still much to be done
As per usual, the factory documentation and download link can be found here.
Update Jan 04, 2010: I was made aware that I embarrassingly enough managed to mix up the minor version number in this release. It's actually 1.2.3 and not 1.2.2 (despite what the post URI says). All docs are now updated to reflect this. With that I take the opportunity to wish everyone a happy new year!
Update 20 November 2011: In an earlier update, I jumped to conclusions that this wouldn't be possible to do with C++11 constexprs, but newer comments have hopefully proven me entirely wrong :) This bodes well for someone creating a better, non-hacky implementation in the future! Also, sorry for the utterly abysmal site update frequency for quite some time now.
When the compiler-adoption of C++11 becomes more commonplace and extensive, we will eventually see the introduction of a language feature known as user-defined literals. This will allow us to transform a constexpr (i.e. known fully at compile-time) string into a variadic template argument list of characters using a special suffix operator, e.g. "hello"_stuff → operator"" _stuff<'h','e','l','l','o'>. This fills a void left by the earlier C++ standards in that it has been impossible for template code to access the contents of a regular string literal.
So why is this interesting? Since we're given the contents of a string at compile-time, it's evident that this is because we would like to process that string somehow at the meta-level, but this is hardly a straight forward task with immutable template programming. In the run-time world we already have excellent parsing support in the form of Boost.Spirit 2.1, ANTLR, YACC et al, but to the best of my knowledge no such solution exists for C++ metaprogramming. This might perhaps be because no one has been crazy enough to attempt it (C++ template programming being infamous for its hilarious error-verbosity and debugging difficulties), but I decided to give developing such a library a go.
This article outlines a highly experimental/prototypical recursive-descent, attribute-based "meta-parser" that is inspired very closely by the concepts found in Boost.Spirit 2.1. In fact, it's sufficiently closely based on them that I would recommend reading the tutorial documentation for its Qi module before continuing to get a feel for what's involved.
Update: added download link for prototype code. Only tested with Visual C++ 2008, very unlikely that it will compile cleanly in GCC et al.
Being able to automatically compute a string hash at compile time can be handy in several situations, such as using them in a switch-case statement, where only integer cases are allowed. The problem with using strings in C++ metaprogramming is that you cannot pass a string literal as a template argument, so hashing solutions have often been done with macro preprocessor magic instead (still with the end result being more of an unrolled hash computation loop rather than just the resulting hash integer itself). It's of course possible to pass argument sequences of single chars to templates, and subsequently calculate a hash using standard template recursion. A lot of single chars as template args do not really make for very pretty reading, however.
Recently, long-time Boost-contributor Eric Niebler has created a string type for the Boost MPL, which can currently be found in the Boost SVN trunk (or, if you're reading this from the glorious world of the future, in the regular Boost distribution. Remember to also pet your robot dog and thank your cyborg butler). The string literal restriction is still very much in place, but mpl::string uses the fairly unknown—and arguably somewhat implementation-defined—existence of multi-character literals to make things more manageable.
I'm going to show how using the MPL allows for quickly and elegantly creating a generalized hashing metafunction that uses the same hashing algorithm as Boost.Functional/Hash and can as a result be compared against runtime values computed by its functions. Please note that this code is something I threw together pretty quickly and doesn't have any accompanied tests, library packaging or anything of that nature. It has only been tested on Visual C++ 2008.
If you want to experiment with mpl::string on Boost 1.38 or below, and you're not synched up against the trunk branch, get char.hpp, char_fwd.hpp, string.hpp and limits/string.hpp from the mpl directory of the SVN trunk and copy them to your mpl directory in the boost include directory.
Just in time for Valentine's day, the perfect gift for your loved one: shiny factory patterns! Truly it will be a day to remember! So what's new, changed or otherwise mangled to bits this time around?
- Added support for smart pointer return values (anything with a nested element_type will be recognized). Breaking change: To reduce code horror and increase uniformity, all abstract types must now be specified as a pointer, be it a raw pointer or a smart pointer. This should hopefully help push the concept that the abstract types' result-type represents what is actually returned by the factory.
- Several throws have been replaced with boost::throw_exception
- Replaced CreatorPolicy and creator_policy_type in prototype<> with ClonePolicy and clone_policy_type, respectively.
- Various code tweaks and changes here and there (but nothing else that should break existing code)
To examplify what the breaking change entails, if you have the following piece of code with version < 1.2.1:
typedef abstract_factory< abstract_soldier , abstract_monster*(const std::string&, int) , abstract_beast > enemy_factory_t;
it will now have to be written like this in 1.2.1 (note the pointer types):
typedef abstract_factory< abstract_soldier* , abstract_monster*(const std::string&, int) , abstract_beast* > enemy_factory_t;
but can also be written with (more or less) smart pointer types, particularly if you want more exception safety in your code:
typedef abstract_factory< std::auto_ptr<abstract_soldier> , boost::shared_ptr<abstract_monster>(const std::string&, int) , std::tr1::shared_ptr<abstract_beast> > enemy_factory_t;
Existing type definitions for concrete factories, as well as calls to create remain unchanged—having to re-specify whether or not the resulting object should be wrapped in a smart pointer here would just introduce redundancy. When passing as individual fields, the full type must be included, though.
For more information about how to deal with this stuff, please refer to the documentation. As always, questions, comments and such are more than welcome.
Since nobody has reported that the previous factory pattern code has attempted to physically or verbally assault them in any way (overly verbose template compilation errors do not count), I'm taking that as a good sign. As such, I have spent quite some time working on a new version with several additions and changes (most should be backwards compatible, but be aware of the namespace change). The most prominent additions/changes are:
- create() can now be called with arguments, which will be forwarded appropriately. Support for argument-forwarding requires only changing the abstract type into a function signature with a pointer return type, e.g. abstract_factory<abstract_foo> → abstract_factory<abstract_foo*(const std::string&)>, and then call my_factory.create<abstract_foo>("foo bar brawl");. Concrete factories need not be changed.
- Added support for constructor argument (re-)binding for concrete factories (think a compile-time version of Boost.Bind for constructors)
- Added support for dynamic creator functions for concrete factories
- All factory classes are now contained within the boost::factory namespace to avoid any naming-conflicts. This is especially important since this isn't an official Boost library, and it would be bad mojo to step on the toes of those that are.
- Moved to proper BoostBook documentation! This is still very much a work in progress, but the tutorial code is fairly complete and should hopefully be descriptive enough for most purposes
The original factory post has been updated, but it should only be seen as an introduction. Please refer to the factory documentation for your various factory cravings, including the download link. If you do not have any factory cravings, but simply like clicking links, it might also be for you.
As before, the code is header-only (except for the unit test file).
In my earlier post about the Visual Studio 2010 Community Tech Preview and its inclusion of a few C++0x features, I briefly touched upon rvalues and move semantics and how they can be used to dramatically speed up the passing of temporary objects. In an attempt to demonstrate, I've whipped up a tiny—admittedly highly unscientific—benchmark just to show the difference between good old copy construction and fancy, shiny new move construction.
C++ is an extremely powerful programming language, but due to its flexiblity and many features, it can take a long time to learn how to use it correctly. I'm going to try to write up some posts every now and then about aspects of the language that come to my mind that might not be immediately obvious to a lot of people, and if I'm lucky someone will actually learn something new from it :)
First up are some semantics of the standard delete-operator, how to properly treat initializer lists and a few words about return value optimizations and why C++0x will be awesome for this.
Update: for those reaching this post from searching Google for "random c++" et al, I assume you're looking for information on the generation of random numbers and not just random C++ nuggets :). For all your random number needs, please refer to the Boost.Random library, which comes packed with a veritable heap of algorithms, such as the famous Mersenne Twister.