保留将来要做的工作清单

Keep a list of work to do in the future

本文关键字:工作 将来 保留      更新时间:2023-10-16

由于函数指针需要提前知道提供了哪些参数,我不知道该怎么做。

本质上,我想要一份工作清单。每个条目都是一个使用特定参数调用的函数。即我想将foo(3, "abcd")添加到工作列表中,然后bar(&h).也就是说,我事先不知道将添加哪些类型的功能。

稍后我将迭代此列表并执行指定的函数调用。

这能实施吗?

您正在寻找std::function和lambdas或std::bind

std::function是任意可调用对象的包装器。您可以在其中存储任何内容,您可以使用适当的参数调用operator()

你可以存储在其中的一件事是lambdas:你将调用和参数封装到一个非参数lambda中并调用它。

您可以存储的另一件事是std::bind.std::bind实际上是一个元函数:它将函数 f 和参数作为输入,并返回一个函数对象,其调用导致在参数上调用f

以下是您如何将其应用于您的案例。常见设置:

std::vector<std::function<void()>> workList;
fillWorkList(workList);
for (auto& f : workList)
f();

这是fillWorkList的两种可能实现。一个有std::bind

void fillWorkList(std::vector<std::function<void()>>& workList)
{
workList.push_back(std::bind(foo, 3, "abcd"));
workList.push_back(std::bind(bar, &h));
}

还有一个带有 lambdas:

void fillWorkList(std::vector<std::function<void()>>& workList)
{
workList.push_back([]() { foo(3, "abcd"); });
workList.push_back([]() { bar(&h); });
}

std::function<void()>表示可以调用的内容,并且不返回任何内容。

最清晰的东西是λ。

std::function<void()> f = []{ foo(3, "abcd"); };

商店"在std::function中呼叫foo( 3, "abcd" );称为f

我们可以建立一个列表 - 一个std::dequestd::vector- 并在以后调用它们。

您可以通过将要捕获的内容放在[]s 中来捕获 lambda 中的状态:

std::function<void()> g = [h]{ bar(&h); };

这会将h复制到 lambda 中,然后使用指向h的指针调用bar。 有时你会希望h是可变的:

std::function<void()> g = [h]()mutable{ bar(&h); };

您还可以使用存储对变量的引用的 lambda。 这是危险的,因为您要对生命周期负责,如果您将 lambda 存储在std::function秒内,然后将它们存储在容器中,则生命周期可能并不简单。

在 C++14 中,您甚至可以将表达式放在[]s 中。

std::function<void()>的行为类似于一个值。 你用()调用它,就像用签名void()调用函数一样。

使用std::bind代替 lambda 在技术上是可行的,但std::bind有许多奇怪的怪癖,生成的代码通常不太清晰,错误几乎总是不可读的。 别这样。

您也可以使用自定义函数对象执行此操作。

struct custom {
std::string s;
void operator()() const {
foo( 3, s );
}
};

然后std::function<void()> f = custom{ "abcd" };另一种说法是你稍后在ff()时会3, std::string("abcd")调用foo

这是一个解决方案,使用参数包和完美的转发,允许使用add(foo, 3, "abcd")

#include <functional>
#include <string>
#include <iostream>
#include <vector>
#include <utility>
void foo(int val, std::string text) { std::cout << val << 't' << text << 'n'; }
void bar(int* ptr) { std::cout << *ptr << 'n'; }
class Worklist {
public:
template <typename ...Args>
void add(Args&&... args) {
worklist.push_back(std::bind(std::forward<Args>(args)...));
}
void do_all()
{
for(auto& i : worklist) {
i();
}
}
std::vector<std::function<void(void)>> worklist;
};
int main()
{
int h{9};
Worklist worklist;
worklist.add(foo, 3, "abcd");
worklist.add(bar,&h);
worklist.do_all();
}

可以编写一个接受 lambda 作为任务的类,而无需使用std::bindstd::function

在这里,一个std::unique_ptr用于存储每个 lambda:

#include <string>
#include <iostream>
#include <vector>
#include <memory>
#include <utility>
void foo(int val, std::string text) { std::cout << val << 't' << text << 'n'; }
void bar(int* ptr) { std::cout << *ptr << 'n'; }
class Generic_Callable {
public:
~Generic_Callable() = default;
virtual void call() = 0;
};
template <typename T>
class MyCallable : public Generic_Callable {
public:
MyCallable(T &&t) : ptr{std::make_unique<T>(std::move(t))} {}
void call() override
{
(*ptr)();
}
std::unique_ptr<T> ptr;
};
class Worklist {
public:
template <typename T>
void add(T &&t)
{
worklist.push_back(std::make_unique<MyCallable<T>>(std::move(t)));
}
void do_all() {
for(auto& i : worklist)
i->call();
}
std::vector<std::unique_ptr<Generic_Callable>> worklist;
};

int main()
{
int h{9};
Worklist worklist;
worklist.add([]() {foo(3, "abcd"); });
worklist.add([&h]() {bar(&h); });
worklist.do_all();
}