I want to achieve something like this:
std::shared_ptr<Factory<BaseClass>> factory =
std::make_shared<Factory<DerivedClass>>();
auto x = factory->create(arg1, arg2, arg3);
Note that in factory->create
, you can pass any arguments to DerivedClass
constructor. It is okay to assume that the BaseClass
constructor and the DerivedClass
are identical.
To avoid the XY Problem, the reason I need this is because I want to use dependency injection (boost::di) to achieve maximum testability.
For example, if there's a class A
that creates Socket
instances, I want it to depend on a Factory<ISocket>
service. In the real code, I'd inject Factory<Socket>
, and in the testing code, I'd inject Factory<Mock<ISocket>>
, so I can test the A
class without actually creating a real socket.
This is my current attempt:
template <typename T>
struct BaseFactory {
virtual std::unique_ptr<T> create() = 0;
};
template <typename TInterface, typename TImplementation>
struct Factory : public BaseFactory<TInterface> {
virtual std::unique_ptr<TInterface> create() override {
return std::make_unique<TImplementation>();
}
};
The current usage is something like:
std::shared_ptr<BaseFactory<ISocket>> factory =
std::make_shared<Factory<ISocket, Socket>>();
auto x = factory->create();
Although not ideal (you need to specify the base class in Factory
), this usage is fine for me and it works.
The next thing I need to add is support for constructor arguments. I've tried to add variadic template to create
:
template <typename ...TArgs>
virtual std::unique_ptr<T> create() = 0;
... but it looks like you can't have virtual methods with templates.
Am I going in the right direction? If yes, how should I add support for constructor arguments in my implementation?
Here is the solution for boost::di:
http://boost-experimental.github.io/di/extensions/index.html#factory