我如何组合多个可变参数模板或拆分参数包?

How can i combine multiple variadic templates or split parameter pack?

我目前正在尝试为 std::functions 定义通用乘法运算符。我想使用多个可变参数模板来做到这一点。部分特化如下所示:

template <typename... _Type> using op_Type = typename std::function<u64(u64, _Type...)>;

inline auto operator*(const op_Type<>& f, const op_Type<>& g) -> op_Type<> {
    return [f, g](u64 num) {
        return f(g(num));
    };
}
template <typename _Ty1, typename _Ty2>
inline auto operator*(const op_Type<_Ty1>& f, const typename op_Type<_Ty2>& g)
-> op_Type<_Ty1, _Ty2> {
    return [f, g](u64 num, _Ty1 arg1, _Ty2 arg2) {
        return f(g(num, arg2), arg1);
    };
}
template <typename _Tyf1, typename _Tyf2, typename _Tyg1, typename _Tyg2>
inline auto operator*(const op_Type<_Tyf1, _Tyf2>& f,
    const typename op_Type<_Tyg1, _Tyg2>& g)
    -> op_Type<_Tyf1, _Tyf2, _Tyg1, _Tyg2> {
    return [f, g](u64 num, _Tyf1 argF1, _Tyf2 argF2, _Tyg1 argG1, _Tyg2 argG2) {
        return f(g(num, argG1, argG2), argF1, argF2);
    };
}

但我需要的是任何泛型 std::functions 采用 u64 值和任意数量的其他参数的相同行为,其应如下所示:

template <typename... _Ty1, template <typename...> class op1 
        , typename... _Ty2, template <typename...> class op2
        , typename... _RetTy, template<typename...> class opRet>
inline auto operator*(const op1<_Ty1...>& f, const op2<_Ty2...> g) -> opRet<_RetTy...> {
    const int size1 = sizeof...(_Ty1);
    const int size2 = sizeof...(_Ty2);
    return [f, g](u64 num, _Ty1 args1..., _Ty2 args2...) {
        auto tmp = g(num, std::forward<_Ty1>(args1)...);
        return f(tmp, std::forward<_Ty2>(args2)...);
    };
}

我也想删除添加的 class 模板,但可能无法使用多个可变参数模板,因为编译器不知道可变参数模板何时结束,对吗? 我想一个好的解决方法是拆分参数包,这样:

template <typename... _Ty1, , typename... _Ty2>
inline auto operator*(const op_type<_Ty1...>& f, const op_type<_Ty2...> g) -> opRet<_Ty1...,_Ty2...> {
    const int size1 = sizeof...(_Ty1);
    const int size2 = sizeof...(_Ty2);
    return [f, g](u64 num, variadic template args...) {
        auto tmp = g(num, split_args(args, 0, size1 - 1));
        return f(tmp, split_args(args, remaining_arguments);
    };
}

其中 split_args return 是输入索引之间的参数,但我不确定如何实现它,有什么想法吗? 我找到了这样的解决方案: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0535r0.html 但我不确定是否有可用的开源代码

编辑: 总之,我需要一个看起来像这样的函数:

template <typename... _Ty1, typename... _Ty2>
   inline auto operator*(const op_type<_Ty1...>& f, const op_type<_Ty2...> g) -> op_type<_Ty1...,_Ty2...> {
        return [f, g](u64 num, _Ty1 args1..., _Ty2 args2...) {
            auto tmp = g(num, std::forward<_Ty1>(args1)...);
            return f(tmp, std::forward<_Ty2>(args2)...);
        };
    }

编辑2: 用法: 假设我有两个功能:

auto f(u64 num, int i, int j) -> u64{
     return num + (i - j)^i;
}

auto g(u64 num, double x){
     return num - int(num / x);
}

那么乘法运算符 h = f*g 应该 return h 为:

auto h(u64 num, int i, int j, double x) -> u64{
     num + (i - j)^i - int(num / x);
}

希望我能如你所愿...


template< typename PACK1, typename PACK2 > struct Combined;

template < typename ... PACK1, typename ... PACK2 >
struct Combined< std::function< uint64_t( uint64_t, PACK1... )>, std::function< uint64_t(uint64_t, PACK2...) > >
{
    using OP_TYPE1 = std::function< uint64_t( uint64_t, PACK1... )>;
    using OP_TYPE2 = std::function< uint64_t( uint64_t, PACK2... )>;

    OP_TYPE1 op1;
    OP_TYPE2 op2;
    Combined( OP_TYPE1 op1_, OP_TYPE2 op2_ ): op1{ op1_}, op2{ op2_}{}

    auto operator( )(uint64_t p1, PACK1... args1, PACK2... args2)
    {
        return op2( op1( p1, args1...), args2...);
    }
};


template < typename OP_TYPE1, typename OP_TYPE2> auto operator*(OP_TYPE1, OP_TYPE2);

template < typename ... PACK1, typename ... PACK2 >
auto operator* ( std::function< uint64_t( uint64_t, PACK1... )> op1, std::function< uint64_t(uint64_t, PACK2...) > op2 )
{
    return Combined< std::function< uint64_t( uint64_t, PACK1... )>, std::function< uint64_t(uint64_t, PACK2...)>>{ op1, op2 };
}

// Example funcs
auto f(uint64_t num, int i, int j) -> uint64_t{
     return num + ((i - j)^i);
}

uint64_t g(uint64_t num, double x){
     return num - int(num / x);
}


int main()
{
    std::function fobject = f;
    std::function gobject = g;

    auto fg = fobject*gobject;

    std::cout << fg( 1, 2, 3, 6.66 ) << std::endl;
}

该示例遗漏了所有可以通过转发参数、移动等进行优化的内容。仅供您捕获签名并从模板参数中获取参数等。