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) );
}
Here is a recursive implementation of a specialized revert<>
:
// forward decl
template<class ...Tn>
struct revert;
// recursion anchor
template<>
struct revert<>
{
template<class ...Un>
static void apply(Un const&... un)
{
ascendingPrint(un...);
}
};
// recursion
template<class T, class ...Tn>
struct revert<T, Tn...>
{
template<class ...Un>
static void apply(T const& t, Tn const&... tn, Un const&... un)
{
// bubble 1st parameter backwards
revert<Tn...>::apply(tn..., t, un...);
}
};
// using recursive function
template<class A, class ...An>
void descendingPrint(A const& a, An const&... an)
{
revert<An...>::apply(an..., a);
}
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).
Beautiful, and looking like a literal translation of Haskell to TMP /smile/. out This looks simple enough. Why do you say "works with gcc 4.8"? Don't you think its Std? I can't see why it weren't. Are you worried about the multiple parameter-packs of
apply
? As far as I remember function-templates can have more then one parameter-pack -- only class-templates can not. Leavesapply(tn..., t, un...)
and the question if the compiler can unroll all the arguments correctly. "Proven by example" (gcc) it seems it should, but does the Standard say so, too?@towi Thanks! I think this is std C++, but gcc 4.8 was the only compiler I have tested. Here is a slightly modified version. Works with gcc 4.6/7/8 and clang, but not with the Intel compiler.
I accepted your answer in favor of the non-recursive ones because I do like recursion myself and this version is the easiest for me to understand.But it was a difficult choice: I urge the readers of this to read the other answers too, of AndyPowl and Xeo, (and maybe the comments) -- they may have benefits you need. And M-M has a point too, if you do not need a general solution.
I think it is worth to mention it here that we always force inlining in such recursion situations, which yield in significant performance gain, even with light optimization.