Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Can you interleave variadic parameters in call sites?

Is it possible to interleave template parameters inside of function call sites?

I effectively want to do implement the following, but I don’t know how (psuedo code):

template <size_t... indices, typename... Ts>
void foo(const Things *things)
{
    static_assert(sizeof...(indices) == sizeof...(Ts));
    constexpr n = sizeof...(Ts);
    bar(
      indices[0], parse<Ts[0]>(things[0]),
      indices[1], parse<Ts[1]>(things[1]),
      ...
      indices[n-1], parse<Ts[n-1]>(things[n-1]));
}

Note: I know the following can be done (psuedo code):

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

template <size_t... indices, typename... Ts>
void foo(const Things *things)
{
    static_assert(sizeof...(indices) == sizeof...(Ts));
    constexpr n = sizeof...(Ts);
    bar(
      indices[0], indices[1], ..., indices[n-1],
      parse<Ts[0]>(things[0]),
      parse<Ts[1]>(things[1]),
      ...
      parse<Ts[n-1]>(things[n-1]));
}

A partial solution I came up with is to add a swizzling component:

template <typename Func>
decltype(auto) swizzle()
{
    return Func();
}

template <typename Func, typename T0>
decltype(auto) swizzle(size_t i0, T0 &&t0)
{
    return Func(i0, std::forward<T0>(t0));
}

template <typename Func, typename T0, typename T1>
decltype(auto) swizzle(size_t i0, size_t i1, T0 &&t0, T1 &&t1)
{
    return Func(i0, std::forward<T0>(t0), i1, std::forward<T1>(t1));
}

but I think I have to manually write each case per arity I want to consider.

>Solution :

Like this:

template <size_t... indices, typename... Ts>
void foo(const Things *things)
{
    std::apply([](auto...args) {
        bar(args...);
    }, std::tuple_cat(std::make_tuple(indices, parse<Ts>(*(things++)))...));
}

If bar is a lambda instead of a function template, you can just pass bar directly as the first argument to std::apply.

If you want to avoid copying the return values of parse<Ts>(*(things++)), you can use std::forward_as_tuple instead of std::make_tuple.

One slightly more verbose alternative if the *(things++) makes you uncomfortable is to use std::index_sequence:

template <size_t... indices, typename... Ts>
void foo(const Things *things)
{
    [=]<auto... Is>(std::index_sequence<Is...>) {
        std::apply([](auto...args) {
            bar(args...);
        }, std::tuple_cat(std::make_tuple(indices, parse<Ts>(things[Is]))...));
    }(std::index_sequence_for<Ts...>());
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading