I have a variadic function zoo which takes N arguments, where N is known at compile time (it is a template parameter of the class containing the function).
template <int N>
struct B
{
template <typename... Args>
static void zoo(Args... args)
{
static_assert(size of...(args) == N, "");
// do something
}
};
I have another variadic function foo which takes M arguments, where M>N and is known at compile time (it is a template parameter of the class containing the function). I have a static index_array containing the indices of the arguments of foo I want to pass to zoo.
From the body of foo I want to call zoo passing a selected subset of the arguments of foo.
What is the best way to do this? Ideally achieving perfect inlining, i.e. so that everything is compiled into just one instruction with no function pointers indirections?
template<int...I>
struct indices
{
static constexpr int N = sizeof...(I);
};
template <int M, typename...X>
struct A
{
// here I am simplifying, in reality IS will be built at compile time based on X
typedef indices<0,2,3> IS;
template <typename... Args>
static void foo(Args... args)
{
static_assert(size of...(args) == M, "");
// do some magic to achieve the function call described in pseudo-code
// B<IS::N>::zoo(args(IS(0),IS(1),IS(2)))
// ideally this should be perfectly inlined to just have the call above
}
};
Please note the code above is a simplification of my problem, designed for the purpose of illustrating the question.
EDIT: As asked below, I describe the use case: I am playing with a template based library to drive micro-controller pins. A micro controller has several ports (accessible as bytes in memory) and each port has up to 8 pins (bits). Class A is a bundle of pins via the template argument X, where every pin is defined as Pin. Class B manipulates all pins on the same port. A::foo is a function to modify some of the pins, with arguments in the same order as the order with which the pins are specified in the X template argument pack. foo needs to group the arguments by ports and dispatch to the B classes which representing individual ports, where all arguments are fused and written to the controller in a single instruction.
To access variadic arguments, we must include the <stdarg. h> header.
Variadic parameters (Variable Length argument) are Python's solution to that problem. A Variadic Parameter accepts arbitrary arguments and collects them into a data structure without raising an error for unmatched parameters numbers.
You can refer VARIADIC FUNCTIONS IN POSTGRESQL for details. See the wiki about Variadic functions: In computer programming, a variadic function is a function of indefinite arity, i.e., one which accepts a variable number of arguments. Support for variadic functions differs widely among programming languages.
A variadic function is designed to accept a variable number of arguments. 1 In JavaScript, you can make a variadic function by gathering parameters. For example: const abccc = (a, b, ... c) => { console.
You can create a helper to extract the nth_arg
like this:
template <int I>
struct ignore
{
template <typename T>
ignore(T&&) // This constructor accepts anything
{
}
};
template <typename T>
struct nth_arg;
template <size_t... DropIndexes>
struct nth_arg<std::integer_sequence<size_t, DropIndexes...>>
{
template <typename Arg, typename... Rest>
static decltype(auto) get(ignore<DropIndexes>..., // ignore args 0...n-1
Arg&& arg,
Rest&&...) // also ignore the rest
{
return std::forward<Arg>(arg); // return nth arg
}
};
And then call
template <int... Is, typename... Args>
static void call_zoo(indices<Is...>, Args&&... args)
{
B<sizeof...(Is)>::zoo(nth_arg<std::make_index_sequence<Is>>::get(
std::forward<Args>(args)...)...);
}
template <int M>
struct A
{
typedef indices<0, 2, 3> IS;
template <typename... Args>
static void foo(Args... args)
{
static_assert(sizeof...(args) == M, "");
call_zoo(IS{}, std::forward<Args>(args)...);
}
};
If you're using C++11, you can easily roll your own integer_sequence
.
Pack the arguments into a tuple of references, and then retrieve them with std::get
and a pack expansion on the indices.
template<class Tuple, int... Is>
static void magic(Tuple&& args, indices<Is...>){
B<IS::N>::zoo(std::get<Is>(std::forward<Tuple>(args))...);
}
template <typename... Args>
static void foo(Args... args)
{
static_assert(sizeof...(args) == M, "");
magic(std::forward_as_tuple(args...), IS{});
}
(You may want to make foo
take forwarding references.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With