【发布时间】:2022-01-05 04:03:27
【问题描述】:
我目前正在尝试为 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)...);
};
}
我也想删除添加的类模板,但可能无法使用多个可变参数模板,因为编译器不知道可变参数模板何时结束,对吧? 我想一个好的解决方法是拆分参数包:
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 返回输入索引之间的参数,但我不确定如何实现它,有什么想法吗? 我找到了这样的解决方案: 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 应该将 h 返回为:
auto h(u64 num, int i, int j, double x) -> u64{
num + (i - j)^i - int(num / x);
}
【问题讨论】:
-
你能解释一下你真正想要做什么吗?我看到很多代码,但我没有明白它应该做什么!
-
我想重载采用两个 std::functions 的乘法运算符,其中每个函数都可以采用任意数量的参数(因此是可变参数模板)。所以一般来说我需要一个在两个不同的可变参数模板上定义的函数,该函数的输入参数是两个带有不同可变参数模板的 std::functions(这里通过 op_type 定义)并返回一个结合这些可变参数模板的函数
-
Q1:两个 std::function 都应该用相同的函数“加载”吗? Q2:组合意味着,你想返回一个 std::function ,它与一个给定的函数对象相同,可能是你的操作符的第一个参数,并返回这个带有两个参数列表的函数对象?这意味着,您的功能对象必须能够自己生成功能对象,对吗?你能在你的例子中展示函数对象和用法吗?
-
如果运算符对象的第一个参数始终是 uint64_t,为什么其他参数不同?
-
A1:不,关键是功能可以不同; A2:通过组合我的意思是,如果一个 std::function 采用 (u64,int,int) 而另一个采用 (u64, double) 乘法产生的 std::function 应该采用 (u64, int, int, double ),所以是的,这两个参数都是 u64 常见的,所以我不需要重复它;作为使用示例,我将编辑问题
标签: c++ variadic-templates template-meta-programming parameter-pack