Can you invert the order of argument-expansion in an initializer-list?

Viewed 89

I am writing a custom interpreted language, which uses a LIFO-stack for data-manipulation. At two places, I need to be able to construct a tuple from values that are stored on the stack. In principle, this code would look like this:

template<typename... Args>
[[nodiscard]] inline std::tuple<Args...> popTupleFromStack(Stack& stack)
{
    return { stack.Pop<Args>()... };
}

However, there is a fundamental problem with the LIFO-ordering of the stack: The initializer-list order dictates that calls happen left-to-right, which means that it would actually try to pop the elements in the completely inverse order. Is there any easy way to inverse this order?

I know that fold-expressions allow you to specify left- or right-folds, but it doesn't seem that you can use fold-expressions when you need to initialize an object with the result.

The closes I've come is manually specifying overloadings for the potential number of arguments in the tuple:

template<typename Arg0>
[[nodiscard]] inline std::tuple<Arg0> popStackTuple(Stack& stack)
{
    return { stack.Pop<Arg0>() };
}

template<typename Arg0, typename Arg1>
[[nodiscard]] inline std::tuple<Arg0, Arg1> popStackTuple(Stack& stack)
{
    Arg1 arg1 = stack.Pop<Arg1>();
    Arg0 arg0 = stack.Pop<Arg0>();

    return { arg0, arg1 };
}

But this obviously limits the number of arguments I can support, and/or results in a lot of "unnecessary" code. And it seems like such a minor thing not being able to be done with modern C++ (I have everything up to, including C++20 at my disposal if it makes any difference).

2 Answers

You might reverse tuple afterward

template <std::size_t ... Is, typename Tuple>
auto reverse_tuple_impl(std::index_sequence<Is...>, Tuple& tuple)
{
    using res_type = std::tuple<std::tuple_element_t<sizeof...(Is) - 1 - Is, std::decay_t<Tuple>>...>;
Is, std::decay_t<Tuple>>>;
    return res_type(std::get<sizeof...(Is) - 1 - Is>(tuple)...);
}

template <typename ... Ts>
auto reverse_tuple(std::tuple<Ts...>& tuple)
{
    return reverse_tuple_impl(std::index_sequence_for<Ts...>(), tuple);
}

Demo

Non a great improvement but... if you can use C++20, so template lambdas, you can embed the helper function inside reverse_tuple()

template <typename ... Ts>
auto reverse_tuple (std::tuple<Ts...> & tuple)
 {
   return [&]<std::size_t ... Is> (std::index_sequence<Is...>)
      { return std::make_tuple(std::get<sizeof...(Is)-1u-Is>(tuple)...); }
    (std::index_sequence_for<Ts...>{});
 }
Related