Как извлечь выбранный набор аргументов вариационной функции и использовать их для вызова другой функции

У меня есть вариационная функция 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 отправкой ссылок.)