我正在尝试在用户定义的函数和数据之间创建一个接口。假设我需要创建一个名为MapFun()
的函数,MapFun()
的输入包括用户定义函数(UDF(句柄和UDF输入。
void userFun1(Data data, int in1, int in2){
// user defined function 1;
}
void userFun2(Data data, int in1, int in2, std::string s){
// user defined function 2;
}
// ...
// apply user function 1 on data
MapFun(@userFun1, data, 3, 4);
// apply user function 2 on data
MapFun(@userFun2, data, 1, 2, "algorithm");
用户将编写userFun
并将其与MapFun()
一起应用。那么,如何设计MapFun()
呢?用户函数可能有不同的输入,并且签名无法预测。此外,MapFun()
不会立即评估userFun
,而是存储所有userFun
并进行懒惰评估。
如有任何建议,我们将不胜感激。
用户函数可能有不同的输入,并且无法预测签名。
这似乎是一个典型的可变模板
此外,
MapFun()
不会立即评估userFun
,而是存储所有userFun
并进行延迟评估。
不一定能理解,但我想您可以使用std::bind()
或lambda函数获得您想要的内容。
我提出了下面的C++14可变模板MapFun()
函数,它返回一个lambda函数,该函数捕获用户函数和参数。该功能可以稍后执行。
template <typename F, typename ... Args>
auto MapFun (F const & f, Args const & ... args)
{ return [=]{ f(args...); }; }
以下是的完整工作示例
#include <iostream>
template <typename F, typename ... Args>
auto MapFun (F const & f, Args const & ... args)
{ return [=]{ f(args...); }; }
void userFun1 (int i1, int i2)
{ std::cout << "uf1, " << i1 << ", " << i2 << std::endl; }
void userFun2 (int i1, int i2, std::string const & s)
{ std::cout << "uf2, " << i1 << ", " << i2 << ", " << s << std::endl; }
int main ()
{
auto l1 = MapFun(userFun1, 1, 2);
auto l2 = MapFun(userFun2, 3, 4, "five");
l2();
l1();
}
如果我理解正确,您只需要存储一个函数和一组参数,以便以后可以调用它们。这正是std::bind
所做的(无论如何,这是它所做的最简单的事情(。事实上,您可以直接使用std::bind
来代替MapFun
:
auto func1 = std::bind(userFun1, data, 3, 4);
auto func2 = std::bind(userFun2, data, 1, 2, "algorithm");
// ... and later,
func1();
func2();
请注意其中的auto
:您不能(便携地(编写std::bind
返回的任何对象的类型,这两个示例对象将具有不同的类型。但这两种类型都会隐式地转换为公共类型CCD_ 19。您可以将一堆std::function<void()>
对象存储在几乎任何您想要的容器类型中,以便稍后使用:
std::map<unsigned int, std::function<void()>> func_map;
func_map[0] = std::bind(userFun1, data, 3, 4);
func_map[1] = std::bind(userFun2, data, 1, 2, "algorithm");
// ...
auto func_iter = func_map.find(key);
if (func_iter != func_map.end() && func_iter->second) {
(func_iter->second)();
}
当然,如果你想使用你的函数名,和/或如果你需要显式的公共返回类型来与其他模板或其他东西一起工作,你可以包装std::bind
:
template <class F, class... Args>
std::function<void()> MapFun(F&& f, Args&&... args) {
return std::bind<void>(std::forward<F>(f), std::forward<Args>(args)...);
}
或者,如果MapFun
应该将可调用对象存储在某个类成员容器或其他容器中,而不仅仅是创建并返回一个(尚不清楚(,那么它当然可以通过使用std::bind
,然后将结果添加到所需的任何容器中来实现这一点。
如果您只需要从C++17备份std::invoke
,那么,它最简单的形式是非常直接的forward
:
template<class F, class... Args> decltype(auto) invoke(F &&f, Args &&...args) {
return ::std::forward<F>(f)(::std::forward<Args>(args)...);
}