英文:
How can I do the type deduction on parameterized template function
问题
#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), ...);
};
template <typename T> struct FunctionWrapper {
template <typename... Args>
static void Call(Args... args) {
T()(args...);
}
};
void FunctionInvokeTest() {
CallFuncs(1, 2, FunctionWrapper<Add<int>>::Call, FunctionWrapper<Mul<int>>::Call);
}
int main() {
FunctionInvokeTest();
return 0;
}
In the code above, I've introduced a FunctionWrapper
template struct that helps you pass template functions like Add
and Mul
as arguments to CallFuncs
without specifying the template parameters explicitly. This allows you to call CallFuncs(1, 2, Add, Mul);
as you desired.
英文:
#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;
}
I want to pass the template function as parameter shown as above. The code works. However I must put <int>
after the function such as Add<int>
.
If this is non-deductible context, then is there another way to allow me write like this, where the Add
and Mul
are still template functions?
CallFuncs(1,2, Add, Mul);
答案1
得分: 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.0, 2.0, Add{}, Mul{});
或者使用显式的类型说明:
CallFuncs<double>(1, 2, Add{}, Mul{});
这与标准库中的“diamond”函数对象非常相似(自从 C++14 起)。例如,std::plus
的声明如下:
template<class T = void>
struct plus;
如果 T
是 void
(例如,在 std::plus<>{}
中),plus::operator()
将推断参数和返回类型。典型的实现如下(经过一些简化):
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);
}
};
英文:
You can't do it directly, but you can turn functions into function objects:
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
will be deduced from the type of a
and b
. In this example it will be int
. To get double
, you need double
parameters:
CallFuncs(1., 2., Add{}, Mul{});
or explicit type specification:
CallFuncs<double>(1, 2, Add{}, Mul{});
This is very similar to "diamond" functors in the standard library (since C++14). For example, the std::plus
declaration is
template<class T = void>
struct plus;
If T
is void
(e.g., in std::plus<>{}
), plus::operator()
deduces argument and return types. Typical implementation looks like this (with some minor simplifications):
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);
}
};
</details>
# 答案2
**得分**: 2
如果您可以将模板函数转换为函数对象类,您可以这样做:
```cpp
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); }); }
英文:
If you can transform your template function into functor class, you might do:
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); }
};
Then you can do
void FunctionInvokeTest() { CallFuncs(1, 2, Add{}, Mul{}); }
Or to have more similar syntax:
constexpr Add add{};
constexpr Mul mul{};
void FunctionInvokeTest() { CallFuncs(1, 2, add, mul); }
If you cannot change your function, wrapping them in lambda might help:
void FunctionInvokeTest() { CallFuncs(1, 2,
[](auto lhs, auto rhs) { Add(lhs, rhs); },
[](auto lhs, auto rhs) { Mul(lhs, rhs); }); }
答案3
得分: 2
将函数参数移入模板的解决方法
template <typename F>
using BinaryOp = void(F, F); // 函数类型
// fns 现在是函数对象的包,而不是类型
template <typename F, BinaryOp<F>... fns>
void CallFuncs(F a, F b) {
(fns(a, b), ...);
};
void FunctionInvokeTest() {
// 现在将函数作为模板参数传递,与所需的数字类型一起
CallFuncs<float, Add, Mul>(1, 2);
}
链接: https://godbolt.org/z/DutpHk
英文:
Workaround by moving function arguments into template
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);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论