I've been running around stack overflow and google for hours now. I can't seem to wrap my head around how to store a function pointer and it's arguments in a wrapper struct.
The following class wraps a function (in this case a packaged task with templated returntypes and arguments). The main part of the wrapper is listed below.
EDIT: The reason why I don't use std::function is because the wrapper (ThreadTask) wraps a std::packaged_task that gets moved into a threadsafe deque. Packaged_task is move-construbable and does not support copy, which std::function do. Therefore I make a custom wrapper.
The compiler gives an error and states that the function doesn't take 0 arguments. But I don't know how to pass along the arguments / store them.
class ThreadTask {
struct BaseInterface {
virtual void Call() = 0;
virtual ~BaseInterface() {};
};
std::unique_ptr<BaseInterface> mImplementation;
template <typename F, typename...Args>
struct BaseFunc : BaseInterface {
F func;
BaseFunc(F&& f, Args... args) : func(std::move(f)) {}
void Call() { func(); }
};
};
I've tried unpacking the arguments in different ways, but I can't seem to make it work. I think I should forward them some how by std::forward, but i can't figure out were to store the parameters
I recommend using std::function
but if you don't want to use that for some reason, you could extend your current class to store the arguments in std::tuple
and then use std::apply
to "unpack" and call the function with the stored arguments.
Example:
class ThreadTask {
public:
struct BaseInterface {
virtual ~BaseInterface() = default;
virtual void operator()() = 0;
};
std::unique_ptr<BaseInterface> mImplementation;
template <typename F, typename... Args>
struct BaseFunc : BaseInterface {
BaseFunc(F f, Args... args)
: func(std::move(f)), m_args{std::move(args)...} {}
void operator()() override {
std::apply(func, m_args);
}
F func;
std::tuple<Args...> m_args;
};
};
Usage example:
void foo(int x, double y) {
std::cout << "got " << x << " and " << y << '\n';
}
int main() {
ThreadTask::BaseFunc bf{&foo, 12, 3.14159};
bf();
}
Note: I changed Call()
to operator()()
which seemed more appropriate and made the members public
for the demo.