C ++需要一个容器来存储用户定义的函数

时间:2018-11-13 01:10:55

标签: c++ c++11 variadic-templates variadic-functions

我正在尝试在用户定义的函数和数据之间创建一个接口。假设我需要创建一个名为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并进行惰性评估。

任何建议都将不胜感激。

3 个答案:

答案 0 :(得分:2)

  

用户功能可能有不同的输入,并且无法预测签名。

这是可变参数模板的典型作品

  

此外,<script src="{{ asset('js/app.js') }}" defer></script> 不会立即评估MapFun(),而是存储所有userFun并进行惰性评估。

不确定,但我想您可以使用userFun或通过lambda函数获得想要的东西。

我建议使用以下C ++ 14可变参数模板std::bind()函数,该函数返回同时捕获用户函数和参数的lambda函数。该功能可以稍后执行。

MapFun()

以下是一个完整的工作示例

template <typename F, typename ... Args>
auto MapFun (F const & f, Args const & ... args)
 { return [=]{ f(args...); }; }

答案 1 :(得分:1)

如果我理解正确,您只想存储一个函数和一组参数,以便以后可以调用它们。这正是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返回的任何对象的类型,而这两个示例对象将具有不同的类型。但是这两个都将隐式转换为通用类型std::function<void()>。您可以在几乎任何所需的容器类型中存储一堆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应该将可调用对象存储在某个类成员容器之内,而不仅仅是创建并返回一个(尚不清楚),它当然可以使用{{1} },然后将结果添加到所需的任何容器中。

答案 2 :(得分:0)

如果您只需要从C ++ 17向后移植Element,那么,它的最简单形式很简单std::invoke

forward