I have a variadic template class which takes two fixed template parameters and additionally a variable list of parameters. When I create an instance I want to specify the first two parameters and have the rest deduced from the arguments passed to the ctor. But it does not work, the variadic part seems always to be empty. I can only create an instance when I specify all the types (including the ctor arguments).
Here is the code I used for testing:
#include <iostream>
#include <tuple>
#include <string>
class Service
{
public:
virtual void Serve() = 0;
};
class InterfaceA : public Service {};
class InterfaceB : public Service {};
class InterfaceC : public Service {};
class ImplementationA : public InterfaceA
{
virtual void Serve() override
{
std::cout << "Implementation A: <null>";
}
};
class ImplementationB : public InterfaceB
{
public:
ImplementationB(int x)
: m_x(x)
{}
virtual void Serve() override
{
std::cout << "Implementation B: " << std::to_string(m_x);
}
private:
int m_x = 0;
};
class ImplementationC : public InterfaceC
{
public:
ImplementationC(std::string str)
: m_str(str)
{}
virtual void Serve() override
{
std::cout << "Implementation C: " << m_str;
}
private:
std::string m_str;
};
template <typename Interface, typename Implementation, typename... CtorArgs>
class Wrapper
{
public:
Wrapper(CtorArgs&&... args)
: m_ctorArgs(std::make_tuple(std::forward<CtorArgs>(args)...))
{}
Service& GetService()
{
m_service = std::apply([](CtorArgs ... ctorArgs)
{
return std::make_unique<Implementation>(ctorArgs...);
},
m_ctorArgs);
return *m_service;
}
private:
std::tuple<CtorArgs ...> m_ctorArgs;
std::unique_ptr<Service> m_service;
};
// deduction guide, not working...
template <typename Interface, typename Implementation, typename... CtorArgs>
Wrapper(int x)->Wrapper<Interface, Implementation, int>;
int main()
{
Wrapper<InterfaceA, ImplementationA> wrapperA;
wrapperA.GetService().Serve();
std::cout << "\n";
// Wrapper<InterfaceB, ImplementationB> wrapperB(7); // NOT OK
Wrapper<InterfaceB, ImplementationB, int> wrapperB(7); // OK
wrapperB.GetService().Serve();
std::cout << "\n";
}
I want to specify services, but create them on demand, when they are needed (due to dependencies between services). I already use factory methods in production code (wrappers which know what parameters to pass to service ctor), but in test code, I want to be able to quickly create a wrapper for mocks and dummy services, which might need different parameters as the production service.
I also tried to specify a deduction guide, but it seems to have no effect...