代码之家  ›  专栏  ›  技术社区  ›  Steven Venham

带数据数组的函数调用的模板参数包扩展

  •  1
  • Steven Venham  · 技术社区  · 7 年前

    试图避免为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 回复  |  直到 7 年前
        1
  •  0
  •   Barry    7 年前

    这应该有效:

    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中实现,你可以在上面找到很多实现。

    关键是,我们建立了这个整数序列,我们可以使用它们来索引到 void* . 这个序列和 Ts ,以便我们可以打开 TS Is 一起。

    注意,这只适用于非- const 指向成员函数的指针。你需要再做一次 康斯特 成员函数。

    此外,如果成员函数接受引用,这将不太起作用-您将需要一些稍微不同的操作。我把那留给读者作为练习。

        2
  •  0
  •   max66    7 年前

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

    如果我正确理解你想要什么,你要找的东西如下

    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" (A) char const * 或A 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 要从中进行铸造的类型 空洞*

    我觉得非常危险但是…如果使用以下方法定义模板

    template <typename T0, typename...>
    using only_first = T0;
    

    你可以用它来强加 调用类函数() 一览表 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.… 铸造 空洞* 指针指向 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);
     }