How to Reverse the Order of Arguments of a Variadic Template Function

How to reverse the order of arguments of a variadic template function?

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).

Reverse variadic template arguments in hierarchy

If all the types in the pack are distinct, you can compute the type's index from the type itself. All that remains is to extract the N - 1 - index'th type from the pack:

template<std::size_t index, class... Ts>
using Nth_type = std::tuple_element_t<index, std::tuple<Ts...>>;

template<class S, class... Ts>
inline constexpr std::size_t type_index = 0;

template<class S, class T, class... Ts>
inline constexpr std::size_t type_index<S, T, Ts...> =
std::is_same_v<S, T> ? 0 : 1 + type_index<S, Ts...>;

template<class T, class... Ts>
using Reverser = Nth_type<sizeof...(Ts) - 1 - type_index<T, Ts...>, Ts...>;

Simple example:

template<class... Ts>
class B;

template<class... Ts>
using RB = B<Reverser<Ts, Ts...>...>; // two pack expansions here

static_assert(std::is_same<RB<>, B<>>());
static_assert(std::is_same<RB<int>, B<int>>());
static_assert(std::is_same<RB<int, float, double>, B<double, float, int>>());

If the pack is allowed to contain identical types, this trick won't work.

This code uses some C++14/17 features. Variable templates are not part of C++11, so type_index has to be implemented differently. Here is a possible implementation.

Iterate in reverse order through the parameter-pack of a variadic template function

Because you should provide, well, template declaration before specializations:

#include <iostream>

template<typename...> void f();

template<>
void f() {}

template<int H, int... T>
void f()
{
f<T...>();
std::cout << H << std::endl;
}

int main()
{
f<1,2,3,42,5>();

return 0;
}

Here we go: https://ideone.com/TZal7p

Reverse order of varidic template arguments while constructing a map key

Since C++17 I would use fold expression (op,...) to do that:

template<class B, class ... Args>
auto key(B base, Args ... args) {
std::common_type_t<Args...> res{};
( (res *= base, res += args % base), ... );
return res;
}

Demo

Does variadic template function call lambda parameter in reverse order?

When an expression that contains a pack expansion is evaluated, the pack is expanded first---which simply instantiates the code, so to speak, without performing any evaluation---then the resulting expression is evaluated according to the usual rules. Your expression

[&](...){}(
(fib(),123)...
);

is expanded into

[&](...){}(
(f1(),123), (f2(),123)
);

and since function arguments are evaluated in an unspecified order, you cannot rely on f2 being called before f1 or vice versa.

Iterating variadic template arguments in reverse order

You're missing a typedef in Mapped_scope_deep_r. This line declares an object, not a type:

typename Mapped_scope_deep_r< typename boost::mpl::at<map, HeadTag>::type::type_map, TailTag...>::type type;

As for reversing the order of a pack, there are some dirty tricks, but the best way is to define a metafunction tuple_reverse and use it to filter the template's input.

How to reverse an integer parameter pack?

How can I reverse the parameter pack <5, 1, 0> to <0, 1, 5> without using any std library functions?

Not sure to understand what do you exactly can use but... it seems easy to me.

Given an helper struct as follows

template <typename, typename>
struct RS_helper;

template <int ... As, int B0, int ... Bs>
struct RS_helper<MetaSequenceOfIntegers<As...>,
MetaSequenceOfIntegers<B0, Bs...>>
: RS_helper<MetaSequenceOfIntegers<B0, As...>,
MetaSequenceOfIntegers<Bs...>>
{ };

template <typename T>
struct RS_helper<T, MetaSequenceOfIntegers<>>
{ using type = T; };

the revert struct can be simply

template <int ... Is>
struct RevertSequence
: RS_helper<MetaSequenceOfIntegers<>, MetaSequenceOfIntegers<Is...>>
{ };

I suppose that a reverse function can be useful

template <int ... Is>
constexpr typename RevertSequence<Is...>::type
revertSequenceFunction (MetaSequenceOfIntegers<Is...> const &)
{ return {}; }

I propose a modified version of your original code with addition of reversed sequence (using also std::cout to print the sequences, but you can remove it, obviously).

#include <iostream>

template <int ...>
struct MetaSequenceOfIntegers
{ };

template <int AccumulatedSize, typename Tn, int ... GeneratedSequence>
struct GeneratorOfIntegerSequence;

template <int AccumulatedSize, typename Grouper, typename Head,
typename ... Tail, int ... GeneratedSequence>
struct GeneratorOfIntegerSequence<AccumulatedSize, Grouper(Head, Tail...),
GeneratedSequence... >
{ typedef typename GeneratorOfIntegerSequence
<AccumulatedSize+sizeof(Head), Grouper(Tail...),
AccumulatedSize, GeneratedSequence...>::type type; };

template <int AccumulatedSize, typename Grouper, int ... GeneratedSequence>
struct GeneratorOfIntegerSequence<AccumulatedSize, Grouper(),
GeneratedSequence...>
{ typedef MetaSequenceOfIntegers<GeneratedSequence...> type; };

template <int ... Sequence>
void intergers_sequencer_generator(MetaSequenceOfIntegers<Sequence...>)
{
using unused = int[];

(void)unused { 0, (std::cout << Sequence << ' ', 0)... };

std::cout << std::endl;
}

template <typename, typename>
struct RS_helper;

template <int ... As, int B0, int ... Bs>
struct RS_helper<MetaSequenceOfIntegers<As...>,
MetaSequenceOfIntegers<B0, Bs...>>
: RS_helper<MetaSequenceOfIntegers<B0, As...>,
MetaSequenceOfIntegers<Bs...>>
{ };

template <typename T>
struct RS_helper<T, MetaSequenceOfIntegers<>>
{ using type = T; };

template <int ... Is>
struct RevertSequence
: RS_helper<MetaSequenceOfIntegers<>, MetaSequenceOfIntegers<Is...>>
{ };

template <int ... Is>
constexpr typename RevertSequence<Is...>::type
revertSequenceFunction (MetaSequenceOfIntegers<Is...> const &)
{ return {}; }

int main ()
{
intergers_sequencer_generator(
GeneratorOfIntegerSequence<0, int(char, int, char)>::type());

intergers_sequencer_generator(
revertSequenceFunction(
GeneratorOfIntegerSequence<0, int(char, int, char)>::type()));
}

How do I iterate (recurse) backwards through a variadic list of template parameters?

This is simple enough to do with an alteration to your Find structure to return the largest matching index instead of the first such (Live at Coliru):

template<typename... Ts>
struct List{
typedef List<Ts...> Type;
enum {
size = sizeof...(Ts)
};
};

template<int I>
using IntType = std::integral_constant<int, I>;

namespace Detail {
template <typename T, typename U>
struct Max : IntType<(U::value > T::value) ? U::value : T::value> {};
template<int I, typename T, typename... Ts>
struct FindLast : IntType<-1>{};
template<int I, typename T, typename U, typename... Ts>
struct FindLast<I, T, U, Ts...> : FindLast<I + 1, T, Ts...>{};
template<int I, typename T, typename... Ts>
struct FindLast<I, T, T, Ts...> : Max<IntType<I>, FindLast<I + 1, T, Ts...>> {};
}

template<typename T, typename U>
struct FindLast;
template<typename T, typename... Ts>
struct FindLast<T, List<Ts...>> : Detail::FindLast<0, T, Ts...>{};

Backward variadic template

As T.C.'s comment below points out, in your first example aa is in a non-deduced context (14.8.2.5 p5 defines non-deduced contexts, including "a function parameter pack that does not occur at the end of the parameter-declaration-list") and so the parameter pack cannot be deduced.

if syntax allows for placing variadic arguments in any place other then the last and under what circumstances?

In addition to the restriction stated above that caused problems for your first example, a template parameter pack has to be the last template parameter unless all following template parameters can be deduced. 14.1 [temp.param] p11:

A template parameter pack of a function template shall not be followed
by another template parameter unless that template parameter can be deduced from the parameter-type-list of the function template or has a default argument (14.8.2).

So this is OK because both template parameter packs can be deduced independently from the function parameters:

template<typename... T, typename... U>
void f(std::tuple<T...>, std::tuple<U...>)
{ }

A different way to write your shift function is to use an index_sequence

#include <tuple>
#include <iostream>

template<typename... T, size_t... I>
void
shift_impl(std::tuple<T...> t, std::index_sequence<I...>)
{
// Use pack expansion with comma operator to populate unused array:
int dummy[] = {
(std::get<I>(t) = std::get<I+1>(t), 0)...
};
}

template<typename T0, typename... T>
void
shift(T0&& arg0, T&&... args)
{
shift_impl(std::tie(arg0, args...), std::index_sequence_for<T...>{});
}

int main()
{
int i = 0, j = 1, k = 2;
shift(i, j, k);
std::cout << i << ' ' << j << ' ' << k << '\n';
}


Related Topics



Leave a reply



Submit