It's possible to fill the appropriate registers of a virtual machine based on the argument list and some logic using a C++17 fold, like so: https://github.com/fwsGonzo/libriscv/blob/master/lib/libriscv/machine_vmcall.hpp#L35
https://github.com/fwsGonzo/libriscv/blob/master/lib/libriscv/machine_vmcall.hpp#L18
Structs will be pushed onto the stack and the address will take up an integer register slot. So, I can turn a regular function call into a call into my virtual machine. I don't think any other programming language can do that.
Now, for the other way around there are system call handlers. They look like this: https://github.com/fwsGonzo/libriscv/blob/master/emulator/src/syscalls.cpp#L20
In an effort to simplify system call handling I want to be able to take a list of argument types, perform some logic on each of them (extract the values based on type), and then optionally call a lambda with the arguments I built up.
The number and types of arguments is known beforehand. The values are not known until they are extracted from the machine registers.
Thanks to @bipll for answering. I chose to implement it like this:
template<typename... Args, std::size_t... indices>
inline auto resolve_args(machine_t& m, std::index_sequence<indices...>)
{
std::tuple<std::decay_t<Args>...> retval;
((std::get<indices>(retval) = m.template sysarg<Args>(indices)), ...);
return retval;
}
template<typename... Args>
inline auto resolve_args(machine_t& m) {
return resolve_args<Args...>(m, std::index_sequence_for<Args...>{});
}