Factory using a variation pattern?

I have an abstract class

template <class T> struct A { /* virtual methods */ }; 

and several specific derived classes with various constructors

 // The constructor of B takes 1 input template <class T> struct B : public A<T> { B() { /* default ctor */ } B( T *input ) { /* initializer */ } // .. implement virtual methods } // The constructor of C takes 2 inputs template <class T> struct C : public A<T> { double some_member; C() { /* default ctor */ } C( T *input, double& value ) { /* initializer */ } // .. implement virtual methods } 

I created a Factory that returns pointers to A , and I'm trying to use Variadic templates to forward input to the constructor of the selected derived class. It works fine, but I had to duplicate the code for cases with / without constructor inputs, and I'm looking for a way to prevent code duplication (see below).

 template <class T> struct A_Factory { typedef std::shared_ptr<A> out_type; // Version without constructor inputs static out_type create( id_type id ) { out_type out; switch (id) { // .. select the derived class case Type_B: out.reset( new B() ); break; } return out; } // Version with constructor inputs template <class... Args> static out_type create( id_type id, Args&&... args ) { out_type out; switch (id) { // .. select the derived class case Type_B: out.reset( new B( std::forward<Args>(args)... ) ); break; } return out; } }; 

Too bad a long question. Any suggestion to make it shorter appreciated.

+7
c ++ c ++ 11 factory-pattern variadic-templates
source share
1 answer

We can solve this using SFINAE and std::is_constructible (h / t Yakk ).

We need only one create function that will send other functions:

 template <class... Args> static std::shared_ptr<A> create( id_type id, Args&&... args ) { switch (id) { case Type_B: return create<B>(std::forward<Args>(args)...); case Type_C: return create<C>(std::forward<Args>(args)...); // ... } 

Each tag-based create function will either call the correct constructor OR return nullptr if one does not exist:

 // possible to construct template <typename T, typename... Args> std::enable_if_t< std::is_constructible<T, Args...>::value, std::shared_ptr<T> > create(Args&&... args) { return std::make_shared<T>(std::forward<Args>(args)...); } // impossible to construct template <typename T, typename... Args> std::enable_if_t< !std::is_constructible<T, Args...>::value, std::shared_ptr<T> > create(Args&&... ) { return nullptr; } 
+11
source share

All Articles