我如何组合多个可变参数模板或拆分参数包?
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;
}
该示例遗漏了所有可以通过转发参数、移动等进行优化的内容。仅供您捕获签名并从模板参数中获取参数等。
我目前正在尝试为 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;
}
该示例遗漏了所有可以通过转发参数、移动等进行优化的内容。仅供您捕获签名并从模板参数中获取参数等。