I have a template function with varargs template arguments, like this
template<typename Args...>
void ascendingPrint(Args... args) { /* ... */ }
And I want to write
template<typename Args...>
void descendingPrint(Args... args) {
/* implementation using ascendingPrint()? */
}
How do I reverse the order of the parameter-pack args
before passing it along, i.e. in pseudo-code:
template<typename Args...>
void descendingPrint(Args... args) {
ascendingPrint( reverse(args) );
}
I think instead of reversing the arguments, you can reverse your logic! For example reverse the operations on arguments.
Output
Here is a recursive implementation of a specialized
revert<>
:It works with gcc-4.6/7/8 and clang and is probably standard compliant -- the only difficult part being the call of
revert<Tn...>::apply(tn..., t, un...)
.It has drawbacks though (as recursion often has), that it generates a lot of template-instantiations of the target function (code bloat) and does not use perfect forwarding, which may be an issue (but maybe could be improved to use it).
Here's the simple approach I mentioned in the comments: Generating indices in reverse and unpacking a tuple with that.
Live example.
My solution supports perfect forwarding and does not involve a recursion:
Live example (or even simplier).
Also modern compilers can perfectly optimize out all the unnecessary stuff: https://godbolt.org/g/01Qf6w
Overall approach and usage
The overal approach consists in packing the arguments into an
std::tuple
of references, exploiting the perfect forwarding machinery ofstd::forward_as_tuple()
.This means that, at run-time, you should incur in very small overhead and no unnecessary copy/move operations. Also, the framework does not use recursion (apart from compile-time recursion, which is unavoidable for generating indices), so no risk of run-time overhead even in case the compiler would not manage to inline the recursive function calls (which is unlikely anyway, so this is more of an academic argument).
Moreover, this solution is general, in that you can use it as a header-only library to invoke your functions with reversed arguments and with minimum effort:
descending_print()
should be just a minimal thin wrapper aroundascending_print()
.Here is how it should look like:
What follows is a presentation of the implementation.
First step: reverting a type sequence
Here is a simple way to revert a type sequence:
A small test program:
And a live example.
Second step: reverting a tuple
The next step consists in reverting a tuple. Given the usual indices trick machinery:
Together with the functions defined above, a tuple can easily be reverted this way:
Here is a simple test program:
Here is a live example.
Third step: reverting a function's arguments
The final step consists in unpacking the tuple when calling our target function. Here is another generic utility to save us a couple of lines:
The above function creates a tuple whose elements are the arguments provided, but in reverse order. We are not ready to define our target:
The above function(s) prints all the arguments provided. And here is how we could write
descending_print()
:A simple test case again:
And of course a live example.
Final step: simplification
The above solution may be non-trivial to understand, but it can be made trivial to use, and quite flexible. Given a couple of generic functions:
And a couple of macro definitions (I couldn't find a way to create an overload set for a function template, sorry):
It becomes really easy to adapt any function for being called with arguments in reverse order:
To conclude, as usual, a live example.