I have a function pointer and parameters, and I'd like to save these and potentially modify them and call the function with them.
I've seen parts of this answered however I'm unsure how a complete solution would look like, I apologize, but I don't really understand parameter packs, and how they relate to tuple.
Here's bits of my code that I'm trying to make work together:
I have this which is basically just calling the function, I think this can be used to save the call into the "callable" structure, to make an interface.
from this question: C++ generic function call with varargs parameter
template<typename R, typename... Args>
auto call(R(*function)(Args...), Args... args) -> typename std::enable_if<!std::is_same<R, void>::value, R>::type
{
return function(args...);
}
template<typename... Args>
void call(void (*function)(Args...), Args... args)
{
function(args...);
}
This structure should store the parameters and the function pointer. (thanks to RaymondChen for pointing out how it should be correctly)
template<typename R, typename... Args>
struct callable
{
R(*function)(Args...);
std::tuple<Args...> params;
callable(Args... argv):
params(std::make_tuple(argv...))
{}
// .....
};
I'm still unsure how to call back the function with the std::tuple
. As far as I understand I should somehow turn the tuple back to Args...
and then call it.
**What I'm trying to achieve:
If you have started storing the function and required parameters for it in the Callable
, I would suggest just provide a operator()
overload for calling the Callable
with its stored parameters.
Something along the line:
// Functor to store the function and its parameters
template<typename R, typename... Args>
class Callable /* final */
{
R(*mFuncPtr)(Args...) { nullptr }; // function pointer.
std::tuple<Args...> mParams{}; // store the parameters as std::tuple
public:
explicit constexpr Callable(R(*func)(Args...))
: mFuncPtr{ func } {}
explicit constexpr Callable(R(*func)(Args...), Args&&... argv)
: mFuncPtr{ func }
, mParams{ std::make_tuple(std::forward<Args>(argv)...) } {}
// optional setter for mParams
void set(Args&&... argv)
{
mParams = std::make_tuple(std::forward<Args>(argv)...);
}
auto operator()() -> std::conditional_t<std::is_void_v<R>, void*, R>
{
if constexpr (std::is_void_v<R>)
{
// invoke the function pointer with tuple pack.
std::apply(mFuncPtr, mParams);
return nullptr; // Use nullptr for void return type
}
else
{
return std::apply(mFuncPtr, mParams);;
}
}
// Print the stored parameters
void printParams() const
{
std::cout << "(";
printParamsImpl(std::index_sequence_for<Args...>{});
std::cout << ")\n";
}
private:
template<std::size_t... I>
void printParamsImpl(std::index_sequence<I...>) const
{
(..., (std::cout << (I == 0 ? "" : ", ") << std::get<I>(mParams)));
}
};