0

I'm attempting to design a factory class that allows me to encapsulate the construction of any class (that has been derived from the same base class "Base"), with any number of constructor arguments. The current design only supports one or zero constructor arguments:

class FactoryBase
{
public:
    FactoryBase(std::string id) : id_(id) {}
    virtual ~FactoryBase(){}
    virtual Base* create() const = 0;
    std::string getId() const { return id_; }
protected:
    std::string id_;
};

template<class T, typename A> //One argument
class Factory : public FactoryBase
{
public:
    Factory(std::string id, A arg) : FactoryBase(id), arg_(arg) {}
    Base* create() const { return new T(arg_); }
private:
    A arg_;
};

template<class T> //zero arguments/default ctor
class Factory<T,void> : public FactoryBase
{
public:
    Factory(std::string id) : FactoryBase(id) {}
    Base* create() const { return new T(); }
};

I could just add one template specialization for each number of arguments, but I'd like to learn how to do it "porperly".

jms
  • 719
  • 2
  • 8
  • 18
  • Yeah, couldn't fix "variadric" to variadic, drove me mad – jms Feb 16 '14 at 20:08
  • Shouldn't `: FactoryBase(id) {}` in the base class be `: id_(id)`? – David G Feb 16 '14 at 20:11
  • FactoryBase::id_ must be initialized in all cases, and in order to enforce that I put it's value as a FactoryBase constructor argument, while providing no default constructor for FactoryBase, so constructors of all derived classes must provide the ID value. – jms Feb 16 '14 at 20:16
  • I meant that in the base class you're recursively calling the constructor `FactoryBase(id)` in the initializer list. That looks like infinite recursion to me. – David G Feb 16 '14 at 20:26
  • Yes, you are right. The excerpt is not from the original program, so I made a mistake while creating the example code. Should be fixed now. – jms Feb 16 '14 at 20:29
  • Sorry. I misread your post. I will make a new answer. – David G Feb 16 '14 at 20:40
  • Yes, this is a duplicate, that result did not show up in my search. – jms Feb 16 '14 at 21:58

1 Answers1

0

Taking from the information I gave in the duplicate, you need to store the types of your arguments in a type list. In C++11 this would be std::tuple. Your class template should take a parameter pack of arguments that are placed into this tuple.

The constructor should be a template constructor that takes a parameter pack, which you then forward to the constructor of the tuple data member.

A compile-time integer sequence generator can be used to access each element of the tuple within create() (see the exact code in the duplicate).

Community
  • 1
  • 1
David G
  • 94,763
  • 41
  • 167
  • 253
  • Is it possible to deduce the `Factory` type from the constructor arguments? I'd like to be able to do the following: `Factory fac1("ID123","arg0", 1.56, 4);` instead of `Factory fac2("ID123","arg0", 1.56, 4);`. – jms Feb 16 '14 at 21:57
  • Of course something like `Factory fac1 = makeFactory("ID123","arg0", 1.56, 4);` would work, but a proper construcor would be neat instead of some external function. – jms Feb 16 '14 at 22:11
  • @user1062874 Sorry but in order for the constructor to work the types have to be known beforehand. This is because the tuple data member needs to have the types specified before the arguments can be forwarded to its constructor. This is why I suggested making a helper function which deduced the types from its parameters. – David G Feb 16 '14 at 22:23