World class C++ factories
published at 01.03.2018 14:20 by Jens Weller
Save to Instapaper Pocket
One of the most popular talks during the review for last years conference, was "The hidden rules of world class C++ code" by Boris Schäling. And indeed, he delivered at the conference. He picked the factory pattern to present his version of world class C++ code, and as it happens to be, I've also have an implementation of this and some experience with boost::factory, which is mentioned in the Bonus Slides of his talk:
My thoughts on his talk are, that it is a very well delivered talk, which speaks to many of us working in OOP dominated code bases. Boris shows very well how one could evolve the traditional version of the factory pattern into something more Modern C++ like. If type erasure is really the tool to use here, is a different question, but its finally a good and understandable example for boost::typeerasure.
I once loved UML, and its diagrams, but also always found it difficult to correctly use it to document generic code, which is the strength of C++: to abstract interfaces and implementations out of the real code into what later could become a library. So when you start from the traditional factory pattern, you might already have the wrong idea of how to implement these hierarchies.
When I started to work on my own CMS, I needed a factory too, and used a "Modern C++ design" inspired implementation together with boost::factory, which is documented in this blog post Building factories with C++ with boost::factory.
And it is still what I use today, with one little change: I got rid of boost::factory. While I was perfectly happy with this working code in my application, when I switched to MSVC for about a month last year, I saw that there was a problem with boost::factory: it wasn't aware or build for move semantics. MinGW had compiled this perfectly, but in MSVC I got a really strange error:
Error: boost\bind\bind.hpp:249: error: C2664: 'Panel *boost::factory::operator ()(void) const': cannot convert argument 1 from 'Widget *' to 'Widget *&'
Thanks to Peter Dimov for solving this riddle on the mailing list, he pointed me at boost::forward_adapter, which acts as a forwarding layer between boost::factory and the actual factory managing code:
factory.registerType(js_typeid,boost::bind<QWidget*>(boost::forward_adapter<boost::factory<ListPanel*>>(boost::factory<ListPanel*>()),_1,_2,_3));
This is an easy fix, and once again shows that every problem in CS is solvable by an additional layer of indirection...
... but I decided to have a more expressive version, then helping boost::factory with an adaptor, as all I need from boost::factory is calling new for a certain object:
template<class RType, class Type = RType> struct type_factory { template<class ...Args> RType* operator()(Args&&... args){return new Type(std::forward<Args>(args)...);} };
This shortens the above code and makes it at the same time much more readable. The generic factory implementation stays untouched.
And that is how factories are currently implemented in my code base. The raw pointer is there, because this code is right now used in a Qt application. And in Qt memory management isn't done with smart pointers, its delegated to the parent usually.
Join the Meeting C++ patreon community!
This and other posts on Meeting C++ are enabled by my supporters on patreon!