I'm writing an object allocator that I'd like to call in the following way:
T result = factoryObject.construct(argA, argB, argC);
I currently have this design, which works...
class Factory {
void* memPool_;
template <typename Tret, typename... Args>
Tret construct(Args&&... args) {
Tret::methodA(std::forward<Args&&>(args));
Tret::Tret(memPool_, std::forward<Args&&>(args);
}
}
... as long as I call it with:
T result = factoryObject.construct<T>(argA, argB, argC);
I want to be able to do it without explicitly specifying T
. T
can get quite complex, and I need to use this factory inline in an initialiser list. I also need to use this in a constructor initialiser list, so I cannot call auto result = factory.construct<T>()
(I simply need it to infer the return type based on what it is constructing).
I have tried inferring the type using the operator() trick (as per https://stackoverflow.com/a/2613010/4649183):
public:
template <class T>
operator T() { return T(); }
};
class GC {
public:
static Allocator Allocate() { return Allocator(); }
};
int main() {
int p = GC::Allocate();
}
... but this does not allow me to pass arguments (since operator()
cannot take arguments). I tried storing Args&& args
as a tuple as a member of Allocator
, repacking the tuple into a parameter pack and calling operator() separately using the logic proposed in the question of Tuple to parameter pack, but
What can I do?
You should have all pieces. Just have to assemble them correctly. Code should be similar to:
template <typename...Ts>
struct Constructor
{
Constructor(void* memPool, Ts... args) :
memPool{memPool},
args{std::forward<Ts>(args)...}
{}
template <typename T>
operator T() && {
return std::apply(
[this](auto&&... args) {
T::methodA(std::forward<Args&&>(args));
return T::T(memPool_, std::forward<Args&&>(args);
},
args);
}
void* memPool_;
std::tuple<Ts...> args;
};
class Factory {
void* memPool_;
template <typename... Args>
Constructor<Args&&...> construct(Args&&... args) {
return {memPool_, std::forward<Args>(args)...};
}
};