I'm trying to write a "factory" class template whose instantiations have variadic constructors which store their arguments in a tuple and later pass on these arguments to the constructors of objects created by the factory.
A minimal example might make it clearer:
#include <memory>
#include <tuple>
struct Foo
{
Foo(int arg1, double arg2)
{}
// ...
};
template<typename T, typename ...ARGS>
class Factory
{
public:
Factory(ARGS&&... args)
: _stored_args(std::make_tuple(std::forward<ARGS>(args)...))
{}
std::unique_ptr<T> create()
{ return std::apply(std::make_unique<T>, _stored_args); }
private:
std::tuple<ARGS...> _stored_args;
};
template<typename T, typename ...ARGS>
std::unique_ptr<Factory<T, ARGS...>> make_factory(ARGS&&... args)
{ return std::make_unique<Factory<T, ARGS...>>(std::forward<ARGS>(args)...); }
int main()
{
auto foo_factory(make_factory<Foo>(1, 2.0));
auto foo_ptr(foo_factory->create());
// ...
}
My problem here is that the call to std::apply
is apparently malformed since both gcc and clang complain along the lines of no matching function for call to '__invoke'
. What am I doing wrong here?
All you need to do is wrap the std::make_unique
call into a perfect-forwarding lambda:
std::unique_ptr<T> create() {
return std::apply(
[](auto&&... xs) {
return std::make_unique<T>(std::forward<decltype(xs)>(xs)...);
},
_stored_args);
}
The reason is that std::make_unique
doesn't only take a T
template argument, but also Args...
, which in this case are deduced by fowarding xs...
. See cppreference.