Freestyling on patterns, idioms and semantics…

Icon

vivid hallucinations for bloodthirsty digital vampires

The Cool Factor(y)

With the coming of C++0x our previous C++ codes seem to have become too boilerplate. Among the number of important changes and improvements over the core language, the one I like most is the variadic template argument, a new semantic that enables the variable number of template arguments for both template classes and functions.

In turn, the variadic template arguments [VTA], along with the r-value reference that allows the perfect forwarding, enable users to design very compact patterns with a high level of code re-usability, opening the doors to a new way of writing generic code.

Up until now, we have emulated VTA by replicating the source code of a class or function, providing the implementation for each number of arguments we wanted it to support. A more elegant way consisted in writing a single generic function (or class) accepting the maximum number of template arguments and providing a placeholder type, like struct null {},  to pad the unused arguments.

These solutions provided the users with the illusion of using VTA on the top of C++03, while leaving the effort of maintaining the boilerplate code to the library implementers, tempted to support a few numbers of arguments, typically four or five (uhm, I’m lazy).

VTAs on the top of C++0x are of a great help when it comes to implement a design pettern. The factory pattern is not an exception.

The factory is a very common pattern. If you have written about a thousand of code lines in your life, probably about 5% of them represent a factory. This pattern is also known as virtual-constructor idiom since it implements a polymorphic generic constructor driven by runtime values.

Some of the valuable points of the factory are listed below:

  • it’s generic and can be reused (the extent of reusabiliy depends on the implementation…)
  • it makes the code clean and extensible (without changing a single line in the client code)

If It’s true that for a library the implementation matters, for a reusable pattern it’s even more important. Basically the implementation of a factory I’m going to present consists in an associative container (a standard map) that maps an identifier into a polymorphic factory allocator, that is a template class in charge of allocating the concrete type, providing the arguments to its constructor.

Compared to the virtual constructor idiom of  Coplien this implementation does not make use of exemplars and that has an evident advantage in term of resource consumption: instances of elements are built on demand and not virtually cloned, nor copy-constructed! That’s a good point because exemplars may acquire resources only released at the factory destruction, or yet they may be not copyable/cloneable at all (because, for instance, just moveable).

In order to exploit the polymorphism the two classes factory_base_allocator and the generic factory_allocator are implemented in a IS-A relation:

template <typename B, typename ... >
struct factory_base_allocator
{
    virtual ~factory_base_allocator()
    {}

    virtual B * alloc(Arg&& ... ) = 0;
};

template <typename B, typename D, typename ... >   // B is a base class of D
struct factory_allocator : public factory_base_allocator<B,Arg...>
{
    static_assert(std::is_base_of<B,D>::value, "base_of relationship violated");

    virtual D * alloc(Arg &&... arg)
    {
        return new D(std::forward<Arg>(arg)...);
    }
};

The factory_base_allocator is a template class: the generic type B is the common base of all the types for whom the factory is the manger. The argument pack Arg is the list of types to be passed to the constructor of the concrete class. Arguments are taken by r-value reference and perfectly forwarded the proper constructor by means of the std::forward, an utility in charge to fix the argument deduction type: r-value if the provided argument is an r-value, l-value otherwise.

The factory_allocator ensures that the type D of the concrete class is in a IS-A  relation with the generic base class (B) my means of the type_trait std:::is_base_of<> and the valuable static_assert. This utility class implements the sole virtual method alloc supposed to construct the instance of D on demand.

Enjoy for a while the beauty of the virtual variadic method alloc: It implements a virtual perfect forwarder, a proof that that the implementation matters!

On the basis of this helper allocator, the implementation of the factory class results:

    template <typename K, typename T, typename ... Arg>
    class factory
    {
    public:
        typedef std::map<K, std::shared_ptr<factory_base_allocator<T,Arg...>>> map_type;

        factory()  = default;
        ~factory() = default;

        bool
        regist(const K & key, factory_base_allocator<T,Arg...> * value)
        { return _M_map.insert( make_pair(key, std::shared_ptr<factory_base_allocator<T,Arg...> >(value) ) ).second; }

        bool
        unregist(const K &key)
        { return _M_map.erase(key) == 1; }

        bool
        is_registered(const K &key) const
        {
            return _M_map.count(key) != 0;
        }

        template <typename ... Ti>
        std::shared_ptr<T>
        operator()(const K &key, Ti&& ... arg) const
        {
            auto it = _M_map.find(key);
            if (it == _M_map.end())
                return std::shared_ptr<T>();
            return std::shared_ptr<T>(it->second->alloc(std::forward<Ti>(arg)...));
        }

    private:
        map_type _M_map;
    };
The complete source code is available here.


Enjoy the C++0x, always.
Advertisements

Filed under: c++, C++11, programming

3 Responses

  1. mak says:

    How about an example showing the usage of the factory?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: