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

C++ need a container to store user defined function

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

非常感谢任何建议。

如果您只需要从 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)...);
}

如果我没理解错的话,你只是想存储一个函数和一组参数,以便以后调用它们。这正是 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 编辑的任何对象的类型 return,并且这两个示例对象将具有不同的类型.但是这两者都会隐式转换为通用类型 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)();
}

当然,如果你想使用你的函数名,and/or如果你需要明确的通用return类型与其他模板或其他东西一起工作,你可以只包装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 应该将可调用对象存储在某些 class 成员容器或其他东西中,而不仅仅是创建和 return 一个(不清楚),它可以当然可以通过使用 std::bind 然后将结果添加到您需要的任何容器中来做到这一点。

User function may have different inputs and the signature can't be predicted.

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

In addition, MapFun() won't evaluate userFun immediately, instead, it stores all userFun and do a lazy evaluation.

不确定是否理解,但我想您可以使用 std::bind() 或使用 lambda 函数获得您想要的东西。

我提出以下 C++14 可变参数模板 MapFun() 函数,return 一个捕获用户函数和参数的 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();
 }