Да, это возможно:
// 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: Как это работает? Сначала мы определяем размер argument packArgs
- sizeof...
. make_indices<N>::type
затем расширяется до indices<0,1,2,...,N-1>
. Он задается в качестве дополнительного параметра для функции реализации (от форвардера, который только создает фиктивный экземпляр), поэтому аргумент дедукции запускается на стороне функции реализации и помещает сгенерированные индексы в пакет аргументов Ns
.
Функция реализации теперь имеет два пакета аргументов с одинаковым размером, а именно Args
и Ns
. При расширении через эллипсис ...
эллипсис расширяет полное выражение , которое оно применяется и оно параллельно расширяет все пакеты параметров! В приведенном выше примере это выражение равно read<Args>(Data, Ns+1)
, которое прекрасно расширяется в псевдокоде OPs.
Я уверен, что вы можете избежать указателя объекта на функцию-указатель. – sellibitze
@sellibitze: Это проблема? Потому что я могу иметь только пользовательские данные указателя void *, которые передаются из функции C. –
Данные могут быть 'void *'. Это функция, которая является «void *», что вызывает беспокойство. –