Как извлечь выбранный набор аргументов вариационной функции и использовать их для вызова другой функции
У меня есть вариационная функция zoo, которая принимает N аргументов, где N известно во время компиляции (это параметр шаблона класса, содержащего функцию).
template <int N>
struct B
{
template <typename... Args>
static void zoo(Args... args)
{
static_assert(size of...(args) == N, "");
// do something
}
};
У меня есть еще одна вариационная функция foo, которая принимает M аргументов, где M > N и известна во время компиляции (это шаблонный параметр класса, содержащего функцию). У меня есть статический index_array, содержащий индексы аргументов foo. Я хочу перейти к zoo.
Из тела foo Я хочу вызвать zoo передачу выделенного подмножества аргументов foo.
Каков наилучший способ сделать это? В идеале достигается идеальная инкрустация, т.е. Так, что все скомпилировано в одну инструкцию без указаний на указатели функций?
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
}
};
Обратите внимание, что приведенный выше код упрощает мою проблему, предназначенную для иллюстрации вопроса.
EDIT:
Как было сказано ниже, я описываю пример использования:
Я играю с библиотекой на основе шаблонов для управления контактами микроконтроллера. Микроконтроллер имеет несколько портов (доступных в виде байтов в памяти), и каждый порт имеет до 8 контактов (бит). Класс A представляет собой пучок контактов через шаблонный аргумент X, где каждый вывод определяется как Pin. Класс B управляет всеми выводами на одном порту. A:: foo - это функция для изменения некоторых контактов, с аргументами в том же порядке, что и порядок, в котором контакты указаны в пакете аргументов шаблона X. foo необходимо сгруппировать аргументы портами и отправить в классы B, которые представляют отдельные порты, где все аргументы объединены и записаны в контроллер в одной команде.
Ответы
Ответ 1
Вы можете создать помощника, чтобы извлечь nth_arg
следующим образом:
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
}
};
И затем вызовите
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)...);
}
};
Если вы используете С++ 11, вы можете легко свернуть свой собственный integer_sequence
.
Ответ 2
Поместите аргументы в кортеж ссылок, а затем извлеките их с помощью std::get
и расширения пакета по индексам.
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{});
}
(Возможно, вы захотите сделать foo
отправкой ссылок.)