Передача позиции вариативного аргумента шаблона

Я хотел бы создать функцию, которая принимает переменное количество аргументов шаблона. Позже с этими аргументами функция должна передать их позицию следующим образом:

template<typename R, typename Args...>
R myFunction(Data &data, void *function) {
    auto f = (R (*)(Args...))function;
    return f(read<Args1>(data, 1), read<Args2>(data, 2), ...);// <-- This is the problem
}

Данный код, конечно, не компилируется. Есть ли способ это исправить? Есть ли способ сделать это без вариативных шаблонов без лишнего дублирования кода?


person Juraj Blaho    schedule 04.03.2013    source источник
comment
Я уверен, что вы можете избежать приведения указателя объекта к указателю на функцию.   -  person sellibitze    schedule 04.03.2013
comment
@sellibitze: это проблема? Потому что у меня могут быть только пользовательские данные указателя void*, которые передаются из функции C.   -  person Juraj Blaho    schedule 04.03.2013
comment
Данные могут быть void *. Проблема заключается в том, что функция является void *.   -  person Vaughn Cato    schedule 04.03.2013
comment
@JurajBlaho: Этот тип приведения крайне непереносим. Я предлагаю вам объяснить, какую проблему вы собираетесь решить таким образом. Скорее всего, вы получите больше полезных ответов, если вы это сделаете. Мне кажется, у нас есть небольшая проблема X/Y.   -  person sellibitze    schedule 04.03.2013
comment
@sellibitze: Спасибо за комментарий, теперь я вижу, что указатель функции приведения к void* является UB. Мне придется решить ее немного по-другому, но я все еще могу решить проблему, используя идеи из принятого ответа.   -  person Juraj Blaho    schedule 05.03.2013
comment
Вместо использования void* для аргумента function я бы добавил еще один параметр шаблона для типа функции, тогда преобразование типов не требуется.   -  person Some programmer dude    schedule 05.03.2013
comment
@JoachimPileborg: Саму эту функцию легко сделать правильно. Но API C, который я должен использовать, может хранить только void* данных. Мне придется обернуть указатель функции в struct.   -  person Juraj Blaho    schedule 05.03.2013


Ответы (1)


Да, это возможно:

// we need a compile-time helper to generate indices
template< std::size_t... Ns >
struct indices
{
  typedef indices< Ns..., sizeof...( Ns ) > next;
};

template< std::size_t N >
struct make_indices
{
  typedef typename make_indices< N - 1 >::type::next type;
};

template<>
struct make_indices< 0 >
{
  typedef indices<> type;
};

С этими помощниками вам нужен один форвардер для вашей функции, например:

template<typename R, typename... Args, std::size_t... Ns>
R myFunctionImpl(void *Data, void *function, indices<Ns...> ) {
    auto f = (R (*)(Args...))function;
    return f(read<Args>(Data, Ns + 1)...);// +1 because indices is zero-based
}

template<typename R, typename... Args>
R myFunction(void *Data, void *function) {
   return myFunctionImpl< R, Args... >( Data, function, typename make_indices<sizeof...(Args)>::type() );
}

EDIT: Как это работает? Во-первых, мы определяем размер пакета аргументов Args через sizeof.... make_indices<N>::type затем расширяется до indices<0,1,2,...,N-1>. Он задается в качестве дополнительного параметра для функции реализации (от пересылки, который просто создает фиктивный экземпляр), поэтому вывод аргументов срабатывает на стороне функции реализации и помещает сгенерированные индексы в пакет аргументов Ns.

Функция реализации теперь имеет два пакета аргументов одинакового размера, а именно Args и Ns. При расширении через многоточие ... многоточие расширяет все выражение, к которому оно применяется, и параллельно расширяет все пакеты параметров! В приведенном выше примере это выражение read<Args>(Data, Ns+1), которое прекрасно расширяется в псевдокод OP.

person Daniel Frey    schedule 04.03.2013
comment
можете опубликовать простой пример? - person BЈовић; 04.03.2013
comment
Я только что сделал. Чего не хватает в приведенном мной примере? - person Daniel Frey; 04.03.2013
comment
Чего не хватает, так это реального примера. С main() и некоторыми функциями (с параметрами 1,2,3). Как вы используете эти функции и структуры? - person BЈовић; 05.03.2013
comment
Мне потребовалось некоторое время, чтобы полностью понять код, и кажется, что он должен работать. - person Juraj Blaho; 05.03.2013
comment
Я все еще не понимаю. Как это: typename make_indices<sizeof...(Args)>::type() компилируется? Должна быть ошибка компиляции. - person BЈовић; 05.03.2013
comment
Это хорошо известная техника, и она компилируется. Я добавил небольшое пояснение к своему ответу. - person Daniel Frey; 05.03.2013