保留将来要做的工作清单

时间:2017-02-17 19:52:59

标签: c++ c++11

由于函数指针需要提前知道提供了哪些参数,所以我不知道如何执行此操作。

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

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

可以实施吗?

4 个答案:

答案 0 :(得分:4)

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

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

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

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

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

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); });
}

答案 1 :(得分:2)

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

存储在其中的最清楚的东西是lambda。

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

存储&#34;在名为foo( 3, "abcd" );的{​​{1}}中致电std::function

我们可以建立一个列表 - fstd::deque - 并在以后调用它们。

您可以通过在std::vector s中放置要捕获的内容来捕获lambda中的状态:

[]

std::function<void()> g = [h]{ bar(&h); }; 复制到lambda中,然后使用指向h的指针调用bar。有时你会希望h是可变的:

h

您还可以使用lambda来存储对变量的引用。这是危险的,因为你负责终生,如果你将lambdas存储在std::function<void()> g = [h]()mutable{ bar(&h); }; 中,然后将它们存储在容器中,那么生命周期可能并不简单。

在C ++ 14中,您甚至可以将表达式放在std::function s。

[]表现得像一个值。您可以使用std::function<void()>调用它,就像调用带有签名()的函数一样。

在技术上可以使用void()而不是lambdas,但是std::bind有许多奇怪的怪癖,生成的代码通常不太清楚,错误几乎总是不可读的。不要这样做。

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

std::bind

然后struct custom { std::string s; void operator()() const { foo( 3, s ); } }; 是另一种方式,当std::function<void()> f = custom{ "abcd" }; foo3, std::string("abcd")时,您将f()调用f

答案 2 :(得分:0)

以下是允许使用add(foo, 3, "abcd")的解决方案using a parameter packperfect forwarding

#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();
}

答案 3 :(得分:0)

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

这里,std::unique_ptr用于存储每个lambdas:

#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();
}