template带有数据数组的函数调用的参数包扩展

时间:2018-06-12 18:22:32

标签: c++ c++11 templates variadic-templates

试图避免为x参数量重载我的函数。

//T.. Types,C Class,R Return type
template<typename R = void,class C,typename T1,typename T2>
R callClassFunction(C& classname,void (C::*func)(T1,T2), void** myd)
{
    return (classname.*func)(*((T1*)myd[0]), *((T2*)myd[1]));
}

是否可以使用可变参数模板执行此操作?

由于数据数组,我无法弄清楚正确的语法。

2 个答案:

答案 0 :(得分:0)

  

是否可以使用可变参数模板执行此操作?

如果我理解你想要什么,你正在寻找以下内容

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');
 }

- 编辑 -

OP问

  

如果我想保留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);
 }

我再说一遍:我发现这非常危险,我很害怕这个解决方案。

但如果你真的想...以下是经过修改的完整工作示例

diff

答案 1 :(得分:0)

这应该有效:

template <typename R, class C, typename... Ts, size_t... Is>
R impl(C& instance, R (C::*func)(Ts...), void** data, index_sequence<Is...>)
{
    return (instance.*pmf)(*static_cast<Ts*>(data[Is])...);
}

template <typename R, class C, typename... Ts>
R callClassFunction(C& instance, R (C::*func)(Ts...), void** data)
{
    return impl(instance, func, data, make_index_sequence<sizeof...(Ts)>{});
}

index_sequence是C ++ 14,但可以在C ++ 11中实现,你可以在SO上找到很多实现。

关键是,我们建立了这个整数序列,我们可以使用它们来索引你的void*。该序列与Ts的大小相同,因此我们可以将TsIs解包在一起。

请注意,这仅适用于指向成员函数的非const指针。您需要再次执行此操作以获取指向const成员函数的指针。

此外,如果成员函数采用参考,这不会很有效 - 您需要稍微不同的操作。我将这作为练习留给读者。