gpt4 book ai didi

c++ - 是否可以将具有不同签名的 lambda 存储在 std::vector 中并在函数中执行它们(使用它们各自的参数)?

转载 作者:行者123 更新时间:2023-12-01 14:40:01 24 4
gpt4 key购买 nike

我正在创建一个类,它允许我存储需要在将来某个时间点执行(按顺序)的 lambda。

class Promise{
private:
//snip//
std::vector<std::function<void()>> lchain;
public:
//snip//
void then(const std::function<void()> &f){
if (this->resolved) {//If the promise is resolved we just call the newly added function, else we add it to the lchain queue that will be processed later
f();
return;
}

lchain.push_back(f);
}
void launch(){
this->resolved = true;
for (auto &fun: this->lchain)
fun();
}
}

很明显,它只适用于带有 [&](){} 等签名的 lambda。但是有些任务需要使用任意数量的任意类型的参数(当函数被添加到队列中时,参数和类型都是预先知道的)。

当前工作的示例驱动程序是
int main(){
Promise* p = new Promise([](){
std::cout << "first" << std::endl;
})->then([](){
std::cout << "second" << std::endl;
});
Promise->launch(); //In my code promise chains are picked up by worker threads that will launch them.
}

我想执行的示例程序:
int main(){
Promise* p = new Promise([](){
return 5;
})->then([](int n){
return n*n;
})->then([](int n){
std::cout << n << std::endl; //Expected output: 25
});
Promise->launch();
}

我正在努力做的事情:
  • 在 std::vector
  • 中存储混合签名的 lambdas
  • 使用与 f
  • 关联的参数使 then() 方法调用 f
  • 使 then() 函数返回 f 的结果,以便将其提供给链中的下一个 lambda(最好在将 lambda 存储到 vector 中之前绑定(bind)它)

  • 我整天都在 stackoverflow 中搜索,但我得到的最接近的是 this但是我希望可以在 then() 方法中做一些事情来简化程序代码,因为在调用 then() 方法之前绑定(bind)每个 lambda 会很痛苦。

    最佳答案

    我有一些我认为可以满足您需求的东西。我将从一个示例开始,然后介绍实现。

    int main(){
    Promise p([] {
    return 5;
    });
    p.then([](int n) {
    return n*n;
    }).then([](int n) {
    std::cout << n << '\n';
    });
    p.launch();

    struct A { int n; };
    struct B { int n; };
    struct C { int n; };

    Promise q([](A a, int n) {
    std::cout << "A " << a.n << ' ' << n << '\n';
    return B{2};
    });
    q.then([](B b) {
    std::cout << "B " << b.n << '\n';
    return C{3};
    }).then([](C c) {
    std::cout << "C " << c.n << '\n';
    });
    q.launch(A{1}, 111);

    Promise<B(A, int)> r([](auto a, int n) {
    std::cout << "A " << a.n << ' ' << n << '\n';
    return B{5};
    });
    r.then([](auto b) {
    std::cout << "B " << b.n << '\n';
    return C{6};
    }).then([](auto c) {
    std::cout << "C " << c.n << '\n';
    });
    r.launch(A{4}, 222);
    }

    这输出:
    25
    A 1 111
    B 2
    C 3
    A 4 222
    B 5
    C 6

    一些缺点:
  • 调用then promise 解决后不会自动调用该函数。在那种情况下事情会变得困惑,我什至不确定这是否可能。
  • 您不能调用then多次在同一个 promise 上。您必须建立一个链并调用then上一个 then 的结果.

  • 如果这些缺点中的任何一个使其无法使用,那么您可以停止阅读这个巨大的答案。

    我们需要的第一件事是获取 lambda 签名的方法。这仅用于演绎指南,因此核心概念并非绝对必要。
    template <typename Func>
    struct signature : signature<decltype(&Func::operator())> {};

    template <typename Func>
    struct signature<Func *> : signature<Func> {};

    template <typename Func>
    struct signature<const Func> : signature<Func> {};

    template <typename Ret, typename... Args>
    struct signature<Ret(Args...)> {
    using type = Ret(Args...);
    };

    template <typename Class, typename Ret, typename... Args>
    struct signature<Ret (Class::*)(Args...)> : signature<Ret(Args...)> {};

    template <typename Class, typename Ret, typename... Args>
    struct signature<Ret (Class::*)(Args...) const> : signature<Ret(Args...)> {};

    template <typename Func>
    using signature_t = typename signature<Func>::type;

    接下来我们需要的是一个基类。我们知道下一个 Promise 必须接受当前 Promise 的返回类型作为参数。所以我们知道下一个 Promise 的参数类型。但是,直到 then 我们才知道下一个 promise 会返回什么。被调用,所以我们需要一个多态基来引用下一个 Promise。
    template <typename... Args>
    class PromiseBase {
    public:
    virtual ~PromiseBase() = default;
    virtual void launch(Args...) = 0;
    };

    现在我们有了 Promise类本身。你可以用函数构造一个 Promise。正如我在上面提到的,一个promise 存储了一个指向链中下一个promise 的指针。 then从给定函数构造一个promise并存储一个指向它的指针。只有一个 next指针,所以您只能调用 then一次。有一个断言可以确保不会发生这种情况。 launch调用存储的函数并将结果传递给链中的下一个promise(如果有的话)。
    template <typename Func>
    class Promise;

    template <typename Ret, typename... Args>
    class Promise<Ret(Args...)> : public PromiseBase<Args...> {
    public:
    template <typename Func>
    explicit Promise(Func func)
    : handler{func} {}

    template <typename Func>
    auto &then(Func func) {
    assert(!next);
    if constexpr (std::is_void_v<Ret>) {
    using NextSig = std::invoke_result_t<Func>();
    auto nextPromise = std::make_unique<Promise<NextSig>>(func);
    auto &ret = *nextPromise.get();
    next = std::move(nextPromise);
    return ret;
    } else {
    using NextSig = std::invoke_result_t<Func, Ret>(Ret);
    auto nextPromise = std::make_unique<Promise<NextSig>>(func);
    auto &ret = *nextPromise.get();
    next = std::move(nextPromise);
    return ret;
    }
    }

    void launch(Args... args) override {
    if (next) {
    if constexpr (std::is_void_v<Ret>) {
    handler(args...);
    next->launch();
    } else {
    next->launch(handler(args...));
    }
    } else {
    handler(args...);
    }
    }

    private:
    using NextPromise = std::conditional_t<
    std::is_void_v<Ret>,
    PromiseBase<>,
    PromiseBase<Ret>
    >;
    std::unique_ptr<NextPromise> next;
    std::function<Ret(Args...)> handler;
    };

    最后,我们有一个扣除指南。
    template <typename Func>
    Promise(Func) -> Promise<signature_t<Func>>;

    这是一个在线 demo .

    关于c++ - 是否可以将具有不同签名的 lambda 存储在 std::vector 中并在函数中执行它们(使用它们各自的参数)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59655732/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com