Можно ли сделать это с помощью шаблона с переменными числами?
Если я правильно понимаю, что вы хотите, вы ищете что-то следующее
template<typename R, class C, typename ... Ts1, typename ... Ts2>
R callClassFunction (C & classname, R (C::*func)(Ts1...), Ts2 && ... as)
{ return (classname.*func)(std::forward<Ts2>(as)...); }
Я имею в виду:
1) тип возвращаемого значения R
может быть выведен из указателя метода, и нет необходимости устанавливать его по умолчанию на void
2) список переменныхаргументов (Ts1...
) также можно вывести из указателя метода
3) для следующего параметра, переданного в callClassFunction()
, для передачи в func()
, я предлагаю другой список переменныхтипы Ts2...
, потому что нет необходимости, чтобы Ts1...
равнялся Ts2...
;нужно только, чтобы типы Ts2...
были преобразованы в типы Ts1...
;таким образом, вы можете передать "123"
(char const *
или char[]
), а не обязательно std::string("123")
, методу, ожидающему std::string
.пример
#include <string>
#include <type_traits>
struct foo
{
long bar (std::string const & a, int b, char c)
{ return a.size() + b + c; }
void baz (std::string const &, int, char)
{ }
};
template<typename R, class C, typename ... Ts1, typename ... Ts2>
R callClassFunction (C & classname, R (C::*func)(Ts1...), Ts2 && ... as)
{ return (classname.*func)(std::forward<Ts2>(as)...); }
int main ()
{
foo f;
auto r { callClassFunction(f, &foo::bar, "123", 4, '5') };
static_assert( std::is_same<long, decltype(r)>{}, "!" );
callClassFunction(f, &foo::baz, "123", 4, '5');
}
- РЕДАКТИРОВАТЬ -
Операционный запрос
Что если я хочу сохранить массив void*
и использую типы Ts1
для приведения из void*
Я нахожу это чрезвычайно опасным, но ... если вы определите шаблон, используя следующее
template <typename T0, typename...>
using only_first = T0;
Вы можете использовать его для наложения в callClassFunction()
списка void *
параметров длиной до Ts1...
(переименован в Ts...
, потому что больше нет Ts2...
)
template<typename R, class C, typename ... Ts>
R callClassFunction (C & classname, R (C::*func)(Ts...),
only_first<void *, Ts> ... as)
и, вВ теле функции вы можете использовать Ts...
, чтобы привести void *
указатели к Ts...
указателям
return (classname.*func)(*static_cast<Ts*>(as)...);
Я повторяю: я нахожу это чрезвычайно опасным, и мне страшно думать об этом решении.
Но если вы действительно хотите ... ниже приведен модифицированный полный рабочий пример
#include <string>
#include <type_traits>
struct foo
{
long bar (int a, double b, char c)
{ return a + b + c; }
void baz (int, double, char)
{ }
};
template <typename T0, typename...>
using only_first = T0;
template<typename R, class C, typename ... Ts>
R callClassFunction (C & classname, R (C::*func)(Ts...),
only_first<void *, Ts> ... as)
{ return (classname.*func)(*static_cast<Ts*>(as)...); }
int main ()
{
foo f;
int i { 1 };
double d { 2.0 };
char c { '3' };
auto r { callClassFunction(f, &foo::bar, (void*)&i, (void*)&d, (void*)&c) };
static_assert( std::is_same<long, decltype(r)>{}, "!" );
callClassFunction(f, &foo::baz, (void*)&i, (void*)&d, (void*)&c);
}