I'm trying to write a variadic template function that includes a loop that iterates over each type in the parameter pack. I'm using this to build up a tuple which I then apply
on the callback function which determined the template types.
I thought I could do this using sizeof...(Args)
as follows:
template <typename ...Args>
void addCallback(void* handle, std::string address, std::function<void(Args...)> callback)
{
return addMessageCallback(std::move(address), [callback](const ci::osc::Message& message) {
std::tuple<Args...> args;
for (size_t i = 0; i < sizeof...(Args); i )
{
std::get<i>(args) = message.getArg<std::tuple_element_t<i, decltype(args)>(i);
}
std::apply(callback, std::move(args));
});
}
This doesn't compile because std::get<i>(args)
requires i
to be a compile time constant. However, all the information is available at compile time. Is there a way to make this work? I've thought about using a fold expression but
I'm using C 17.
CodePudding user response:
You can define a helper function to use index_sequence
to expand the elements of Tuple
and assign values through fold expression.
template<class Tuple, class Message, std::size_t... Is>
void assign_tuple(Tuple& tuple, const Message& message, std::index_sequence<Is...>) {
((std::get<Is>(tuple) = message.getArg<std::tuple_element_t<Is, Tuple>(Is)), ...);
};
template <typename ...Args>
auto addCallback(void* handle, std::string address, std::function<void(Args...)> callback) {
return addMessageCallback(std::move(address), [callback](const ci::osc::Message& message) {
std::tuple<Args...> args;
assign_tuple(args, message, std::make_index_sequence<sizeof...(Args)>{});
std::apply(callback, std::move(args));
});
}
In C 20 you can just define template lambda inside the function to do this.