Search code examples
c++templatesfactory-pattern

Call constructor of template parameter


Given a templated factory method, I would like to call different constructors based on the constructors the template parameter provides:

template<typename T>
T* Factory::create()
{
  if (hasOnlyDefaultConstructor<T>())
    return new T();
  else
    return new T(this);
}

Two problems:

  • If T does not have a constructor T(Factory*), then there are compilation problems.
  • How to write hasOnlyDefaultConstructor()?

In general I would like the following:

template<typename T>
T* Factory::create()
{
  if (hasDefaultConstructor<T>())
    return new T();
  else if (hasUnaryConstructor<T>())
    return new T(create());
  else if (hasBinaryConstructor<T>())
    return new T(create(), create());
  else ....
}

Is there a way to achieve this in C++? I understand the problems if there are multiple constructors for the compiler to choose, but let's say that we only pass types T which have exactly one public constructor.

class A 
{
  A(B* b);
}

class B 
{
  B(C* c, D* d);
}  

A* a = Factory::create<A>(); // same as A* a = new A(new B());
B* b = Factory::create<B>(); // same as B* b = new B(new C(), new D());

Shouldn't it be possible to write a generic function create(), which could instantiate both B and A?


Solution

  • You may want this:

    struct X
    {
      enum {TYPE = 0;}// has default constructor
      X() {}
    };
    
    
    struct A
    {
      enum {TYPE = 1;}
      typedef B P;
      A(P* p) {}
    };
    
    struct B
    {
      enum {TYPE = 2;}
      typedef C P1;
      typedef D P2;
      B(P1* p1, P2* p2) {}
    };
    
    template<T, type> //type default = 0
    struct FactoryDetail<T>
    {
      static T* create(){return new T(); } 
    };
    
    template<T>
    struct FactoryDetail<T, 1>
    {
      static T* create(){return new T(new typename T::P()); } 
    };
    
    template<T>
    struct FactoryDetail<T, 2>
    {
      static T* create(){return new T(new typename T::P1(), new typename T::P2()); } 
    };
    
    //final Factory
    template<T>
    struct Factory
    {
      static T* create(){return FactoryDetail<T, T::TYPE>::create(); } 
    };
    

    I don't have dev environment now, the above codes describing the basic idea.