C++ Template to implement the Factory Pattern Design

A template class that will create a concrete instance of an interface class when given the name (as a string) of the concrete class.

This design is often seen in code, so the purpose of this class is to reduce the boilerplate code needed to write a factory class. 

The template class will be used like this:

using MyFactory = factory&lt;MyInterfaceType, MyType_1, MyType_2, MyType_3&gt;;

int main() {
    auto ptr = MyFactory::create("MyType_1");
    ptr-&gt;doSomething();
}


There will be a static assert to check that all of the concrete types inherit from the interface type and the create method can accept an optional argument to describe the return type if no class matching the id is found.

Implementation

template&lt;typename interface_type, typename... products&gt;
struct factory {

    template&lt;typename Class&gt;
    struct LabledClass {
        std::string_view label = to_string&lt;Class&gt;();
        Class data;
    };

    using labled_classes = std::tuple&lt;LabledClass&lt;products&gt;...&gt;;

    static std::unique_ptr&lt;interface_type&gt; create(const std::string_view&amp; id, std::unique_ptr&lt;interface_type&gt; default_type = nullptr) {
        std::unique_ptr&lt;interface_type&gt; result = std::move(default_type);

        //checl all products inherit from interface_type
        std::apply([](auto&amp;&amp;... tuple_elem) {
            ((static_check&lt;decltype(tuple_elem.data)&gt;()), ...);
        }, labled_classes{} );

        //if product matches id, return a new instance of that product
        std::apply([&amp;result, &amp;id](auto&amp;&amp;... tuple_elem) {
            (( tuple_elem.label == id ? result = std::make_unique&lt;decltype(tuple_elem.data)&gt;() : result ), ...);
        }, labled_classes{} );

        return result;
    }

private:
    template&lt;typename product&gt;
    static void static_check() {
        static_assert(std::is_base_of&lt;interface_type, product&gt;::value, "all products must inherit from interface_type");
    }
};


This requires the function to_string&lt;Class&gt;() which does not yet exist in the c++ standard, but can be implemented on GCC or Clang like so:

template&lt;typename Class&gt;
constexpr std::string_view to_string() {
    std::string_view str = __PRETTY_FUNCTION__;
    auto first = str.find("= ");
    std::string_view str2 = str.substr(first + 2);
    auto last = str2.find(";");
    str2.remove_suffix(str2.length() - last);
    return str2;
}


Example use

#include &lt;iostream&gt;
#include "factory.h"

struct Animal {
    virtual void makeNoise() const = 0;
};

struct Dog : Animal {
    virtual void makeNoise() const override{
        std::cout &lt;&lt; "Woof" &lt;&lt; std::endl;
    }
};

struct Cat : Animal {
    virtual void makeNoise() const override{
        std::cout &lt;&lt; "Meow" &lt;&lt; std::endl;
    }
};

struct Duck : Animal {
    virtual void makeNoise() const override{
        std::cout &lt;&lt; "Quack" &lt;&lt; std::endl;
    }
};

struct NullAnimal : Animal {
    virtual void makeNoise() const override{
        std::cout &lt;&lt; "?" &lt;&lt; std::endl;
    }
};


using AnimalFactory = factory&lt;Animal, Dog, Cat, Duck&gt;;

int main() {
    auto animal = AnimalFactory::create("Dog");
    animal-&gt;makeNoise();
}


I have tested this with GCC 9.01 and it works
Seems pretty reasonable. I mean, I definitely wouldn't put this in production code because it relies on parsing a class name out of __PRETTY_FUNCTION__, and that's not necessarily guaranteed to keep working in future versions of GCC let alone Clang (and __PRETTY_FUNCTION__ isn't even supported at all on MSVC; they have __FUNC_SIG instead).

In fact, I just tested on Godbolt, and your to_string&lt;T&gt;() function doesn't work at all on Clang. Furthermore, even on GCC, it has trouble with corner cases like A&lt;';'&gt; — https://godbolt.org/z/UNVRQL



Nitpicks on your test code: The rule of thumb I follow is that every polymorphic method should have exactly one of virtual, override, or final (and really nothing should ever have final). So your repetition of virtual is just clutter, to me.

Ditto your use of std::endl (which flushes) versus plain old "\n" (which also flushes if you're outputting to a line-buffered stream such as std::cout). You could save some typing there.



You misspell "labeled" in at least two places: LabledClass and labled_classes. These are implementation details, but it's still important to spell things right so that you can grep for them later.

You pass const std::string_view&amp; id by reference. This is unidiomatic. string_view is already a trivially copyable type, the size of two pointers. It doesn't make sense to force one of those onto the stack just so you can take its address and pass it by reference. Pass string_view by value.



    //checl all products inherit from interface_type
    std::apply([](auto&amp;&amp;... tuple_elem) {
        ((static_check&lt;decltype(tuple_elem.data)&gt;()), ...);
    }, labled_classes{} );


Typo: checl for check. And this is waaay more complicated than it needs to be. Just static_assert the thing you want to assert:

static_assert(std::is_base_of_v&lt;interface_type, products&gt; &amp;&amp; ...);


In fact, let's use the idiomatic CamelCase for template arguments, and keep them short:

template&lt;class Base, class... Ps&gt;
[...]
    static_assert(std::is_base_of_v&lt;Base, Ps&gt; &amp;&amp; ...);




std::apply([&amp;result, &amp;id](auto&amp;&amp;... tuple_elem) {
    (( tuple_elem.label == id ?
       result = std::make_unique&lt;decltype(tuple_elem.data)&gt;() :
       result ), ...);
}, labled_classes{} );


This complexity is a little more irreducible, but still, doing it all with a tuple and std::apply seems like way more template instantiations than you really ought to have here. What's wrong with a good old-fashioned chain of ifs?

Also, nit: if you're capturing everything by reference, just write [&amp;]. It saves brain cells for the reader of your code.

int dummy[] = {
    ([&amp;]() { if (id == to_string&lt;Ps&gt;()) result = std::make_unique&lt;Ps&gt;(); }(), 0) ...
};


We could even short-circuit as soon as we find the match. That's easy if we leave result null at first; then result will be null if and only if we should still be doing string comparisons.

static std::unique_ptr&lt;Base&gt;
create(std::string_view id, std::unique_ptr&lt;Base&gt; default_type = nullptr)
{
    static_assert(std::is_base_of_v&lt;Base, Ps&gt; &amp;&amp; ...);

    std::unique_ptr&lt;Base&gt; result = nullptr;
    int dummy[] = {
        ([&amp;]() {
            if (result == nullptr &amp;&amp; id == to_string&lt;Ps&gt;()) {
                result = std::make_unique&lt;Ps&gt;();
            }
        }(), 0) ...
    };
    if (result == nullptr) {
        result = std::move(default_type);
    }
    return result;
}


At this point it's no longer clear why you need struct factory at all. So personally I'd get rid of it, and rename the now-free function create to makeUniqueByName or something.