Reordering Variadic Parameters
Posted
by
void-pointer
on Stack Overflow
See other posts from Stack Overflow
or by void-pointer
Published on 2012-07-02T17:40:54Z
Indexed on
2012/07/05
3:16 UTC
Read the original article
Hit count: 195
I have come across the need to reorder a variadic list of parameters that is supplied to the constructor of a struct. After being reordered based on their types, the parameters will be stored as a tuple. My question is how this can be done so that a modern C++ compiler (e.g. g++-4.7
) will not generate unnecessary load or store instructions. That is, when the constructor is invoked with a list of parameters of variable size, it efficiently pushes each parameter into place based on an ordering over the parameters' types.
Here is a concrete example. Assume that the base type of every parameter (without references, rvalue references, pointers, or qualifiers) is either char
, int
, or float
. How can I make it so that all the parameters of base type char
appear first, followed by all of those of base type int
(which leaves the parameters of base type float
last). The relative order in which the parameters were given should not be violated within sublists of homogeneous base type.
Example: foo::foo()
is called with arguments float a, char&& b, const float& c, int&& d, char e
. The tuple tupe is std::tuple<char, char, int, float, float>
, and it is constructed like so: tuple_type{std::move(b), e, std::move(d), a, c}
.
Consider the struct defined below, and assume that the metafunction deduce_reordered_tuple_type
is already implemented. How would you write the constructor so that it works as intended? If you think that the code for deduce_reodered_tuple_type
, would be useful to you, I can provide it; it's a little long.
template <class... Args> struct foo
{
// Assume that the metafunction deduce_reordered_tuple_type is defined.
typedef typename deduce_reordered_tuple_type<Args...>::type tuple_type;
tuple_type t_;
foo(Args&&... args) : t_{reorder_and_forward_parameters<Args>(args)...} {}
};
Edit 1 The technique I describe above does have applications in mathematical frameworks that make heavy use of expression templates, variadic templates, and metaprogramming in order to perform aggressive inlining. Suppose that you wish to define an operator that takes the product of several expressions, each of which may be passed by reference, reference to const, or rvalue reference. (In my case, the expressions are conditional probability tables and the operation is the factor product, but something like matrix multiplication works suitably as well.)
You need access to the data provided by each expression in order to evaluate the product. Consequently, you must move the expressions passed as rvalue references, copy the expressions passed by reference to const, and take the addresses of expressions passed by reference. Using the technique I describe above now poses several benefits.
- Other expressions can use uniform syntax to access data elements from this expression, since all of the heavy-lifting metaprogramming work is done beforehand, within the class.
- We can save stack space by grouping the pointers together and storing the larger expressions towards the end of the tuple.
- Implementing certain types of queries becomes much easier (e.g. check whether any of the pointers stored in the tuple aliases a given pointer).
Thank you very much for your help!
© Stack Overflow or respective owner