I have this c++ template function
template <int N, int B, auto... Args>
void somefunc() {
// do work...
}
, which I can call like this:
somefunc<1, true, 2, false>();
I want to expand the API so that clients can call somefunc
like this as well:
somefunc<Pack<1, true>, Pack<2, false>>(); // equivalent to somefunc<1, true, 2, false>()
, where Pack
is some struct:
template <int N, bool B>
struct Pack
{
static constexpr int value = N;
static constexpr int flag = B;
};
A straightforward approach would be to try something like this:
template <typename... Packs>
void somefunc() {
somefunc<Packs::value..., Packs::flag...>();
}
But this expands to:
somefunc<1, 2, true, false>();
instead of to:
somefunc<1, true, 2, false>();
Is there a simple way to expand the API in the way described?
To flatten Packs, you might use std::tuple
:
template <typename... Packs>
void somefunc() {
constexpr std::tuple t = std::tuple_cat(std::tuple{Packs::value, Packs::flag}...);
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
return somefunc<std::get<Is>(t)...>();
}(std::make_index_sequence<std::tuple_size_v<decltype(t)>>());
}
or with std::apply
which requires to wrap constants into std::integral_constant
as regular function parameters are not constexpr
.
template <typename... Packs>
void somefunc() {
constexpr std::tuple t =
std::tuple_cat(std::tuple{std::integral_constant<int, Packs::value>{},
std::integral_constant<int, Packs::flag>{}}...);
return std::apply([](auto... args){ somefunc<args()...>(); }, t);
}