#include <iostream>
template <typename... Ts> void Print(Ts... args) {
(std::cout << ... << args) << std::endl;
}
template <typename T> void Add(T a, T b) { Print(a + b); }
template <typename T> void Sub(T a, T b) { Print(a - b); }
template <typename T> void Mul(T a, T b) { Print(a * b); }
template <typename F, typename... Fns> void CallFuncs(F a, F b, Fns... fns) {
(fns(a, b), ...);
};
void FunctionInvokeTest() { CallFuncs(1, 2, Add<int>, Mul<int>); }
int main() {
FunctionInvokeTest();
return 0;
}
我想将模板函数作为参数传递,如上所示。该代码有效。但是,我必须在<int>
之类的函数之后放置Add<int>
。
如果这是不可扣除的上下文,那么还有另一种方法可以让我这样写吗,其中Add
和Mul
仍然是模板函数?>
CallFuncs(1,2, Add, Mul);
答案 0 :(得分:3)
您不能直接执行操作,但是可以将函数转换为函数对象:
struct Add {
template<typename T>
void operator()(T a, T b) {
Print(a + b); }
};
struct Mul {
template<typename T>
void operator()(T a, T b) {
Print(a * b); }
};
template<typename F, typename... Fns>
void CallFuncs(F a, F b, Fns... fns) {
(fns(a, b), ...);
};
void FunctionInvokeTest() {
CallFuncs(1, 2, Add{}, Mul{});
}
T
将根据a
和b
的类型推导。在此示例中,它将为int
。要获取double
,您需要double
参数:
CallFuncs(1., 2., Add{}, Mul{});
或显式类型说明:
CallFuncs<double>(1, 2, Add{}, Mul{});
这与标准库(自C ++ 14起)中的“钻石”函子非常相似。例如,std::plus
声明是
template<class T = void>
struct plus;
如果T
为void
(例如,在std::plus<>{}
中),则plus::operator()
推导参数和返回类型。典型的implementation看起来像这样(有一些小的简化):
template<> struct plus<void> {
template<typename Tp, typename Up>
constexpr auto operator()(Tp&& t, Up&& u) const {
return std::forward<Tp>(t) + std::forward<Up>(u);
}
};
答案 1 :(得分:2)
如果您可以将模板函数转换为函子类,则可以这样做:
struct Add {
template <typename T>
void operator ()(T a, T b) const { Print(a + b); }
};
struct Sub
{
template <typename T> void operator() (T a, T b) const { Print(a - b); }
};
struct Mul
{
template <typename T> void operator() (T a, T b) const { Print(a * b); }
};
那你就可以做
void FunctionInvokeTest() { CallFuncs(1, 2, Add{}, Mul{}); }
或者具有更多类似的语法:
constexpr Add add{};
constexpr Mul mul{};
void FunctionInvokeTest() { CallFuncs(1, 2, add, mul); }
如果您无法更改函数,则将它们包装在lambda中可能会有所帮助:
void FunctionInvokeTest() { CallFuncs(1, 2,
[](auto lhs, auto rhs) { Add(lhs, rhs); },
[](auto lhs, auto rhs) { Mul(lhs, rhs); }); }
答案 2 :(得分:2)
通过将函数参数移到模板中的解决方法
template <typename F>
using BinaryOp = void(F, F); // function type
// fns is now a pack of function objects instead of types
template <typename F, BinaryOp<F>... fns>
void CallFuncs(F a, F b) {
(fns(a, b), ...);
};
void FunctionInvokeTest() {
// the functions are now passed as template arguments alongside the desired numeric type
CallFuncs<float, Add, Mul>(1, 2);
}