将 packaged_task 移至 lambda

发布于 2024-10-08 00:43:39 字数 1694 浏览 0 评论 0原文

我想在 lambda 中移动并调用 boost::packaged_task 。

但是,我无法找出一个优雅的解决方案。

例如这不会编译。

        template<typename Func>
        auto begin_invoke(Func&& func) -> boost::unique_future<decltype(func())> // noexcept
        {   
            typedef boost::packaged_task<decltype(func())> task_type;

            auto task = task_type(std::forward<Func>(func));
            auto future = task.get_future();

            execution_queue_.try_push([=]
            {
                try{task();}
                catch(boost::task_already_started&){}
            });

            return std::move(future);       
        }

    int _tmain(int argc, _TCHAR* argv[])
    {
        executor ex;
        ex.begin_invoke([]{std::cout << "Hello world!";});
       //error C3848: expression having type 'const boost::packaged_task<R>' would lose some const-volatile qualifiers in order to call 'void boost::packaged_task<R>::operator ()(void)'
//          with
//          [
//              R=void
//          ]
        return 0;
    }

我相当丑陋的解决方案:

    struct task_adaptor_t
    {
        // copy-constructor acts as move constructor
        task_adaptor_t(const task_adaptor_t& other) : task(std::move(other.task)){}
        task_adaptor_t(task_type&& task) : task(std::move(task)){}
        void operator()() const { task(); }
        mutable task_type task;
    } task_adaptor(std::move(task));

    execution_queue_.try_push([=]
    {
        try{task_adaptor();}
        catch(boost::task_already_started&){}
    });

将 packaged_task 移动到调用它的 lambda 中的“正确”方法是什么?

I want to move and call a boost::packaged_task inside a lambda.

However, I can't figure out an elegant solution.

e.g. This won't compile.

        template<typename Func>
        auto begin_invoke(Func&& func) -> boost::unique_future<decltype(func())> // noexcept
        {   
            typedef boost::packaged_task<decltype(func())> task_type;

            auto task = task_type(std::forward<Func>(func));
            auto future = task.get_future();

            execution_queue_.try_push([=]
            {
                try{task();}
                catch(boost::task_already_started&){}
            });

            return std::move(future);       
        }

    int _tmain(int argc, _TCHAR* argv[])
    {
        executor ex;
        ex.begin_invoke([]{std::cout << "Hello world!";});
       //error C3848: expression having type 'const boost::packaged_task<R>' would lose some const-volatile qualifiers in order to call 'void boost::packaged_task<R>::operator ()(void)'
//          with
//          [
//              R=void
//          ]
        return 0;
    }

My rather ugly solution:

    struct task_adaptor_t
    {
        // copy-constructor acts as move constructor
        task_adaptor_t(const task_adaptor_t& other) : task(std::move(other.task)){}
        task_adaptor_t(task_type&& task) : task(std::move(task)){}
        void operator()() const { task(); }
        mutable task_type task;
    } task_adaptor(std::move(task));

    execution_queue_.try_push([=]
    {
        try{task_adaptor();}
        catch(boost::task_already_started&){}
    });

What is the "proper" way to move a packaged_task into a lambda which calls it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

凝望流年 2024-10-15 00:43:39

通过正确实现 std::bind (或与启用移动的类型等效的东西),您应该能够将 bind 和 C++0x lambda 结合起来,如下所示:

task_type task (std::forward<Func>(func));
auto future = task.get_future();

execution_queue_.try_push(std::bind([](task_type const& task)
{
    try{task();}
    catch(boost::task_already_started&){}
},std::move(task)));

return future;

顺便说一句:您不需要 std::move围绕 future 因为 future 是一个本地对象。因此,它已经受到潜在的复制省略的影响,如果编译器无法执行该省略,则它必须从“未来”移动构造返回值。在这种情况下显式使用 std::move 实际上可能会抑制复制/移动省略。

With a proper implementation of std::bind (or something equivalent with respect to move-enabled types) you should be able to combine bind and a C++0x lambda like this:

task_type task (std::forward<Func>(func));
auto future = task.get_future();

execution_queue_.try_push(std::bind([](task_type const& task)
{
    try{task();}
    catch(boost::task_already_started&){}
},std::move(task)));

return future;

btw: You don't need a std::move around future because future is a local object. As such, it's already subject to potential copy elision and if the compiler is not able to do that elision it has to move construct the return value from 'future'. The explicit use of std::move in this case may actually inhibit a copy/move elision.

超可爱的懒熊 2024-10-15 00:43:39

我发布了一个关于转向 lambda 的类似问题。 C++0x 没有任何移动捕获语法。我能想到的唯一解决方案是某种代理函数对象。

template<typename T, typename F> class move_capture_proxy {
    T t;
    F f;
public:
    move_capture_proxy(T&& a, F&& b) 
        : t(std::move(a)), f(std::move(b)) {}
    auto operator()() -> decltype(f(std::move(b)) {
        return f(std::move(b));
    }
};
template<typename T, typename F> move_capture_proxy<T, F> make_move_proxy(T&& t, F&& f) {
    return move_capture_proxy<T, F>(std::move(t), std::move(f));
}

execution_queue.try_push(make_move_proxy(std::move(task), [](decltype(task)&& ref) {
    auto task = std::move(ref);
    // use task
});

请注意,我实际上并没有尝试过这段代码,如果使用可变参数模板,它会变得更好,但 MSVC10 没有它们,所以我不太了解它们。

There's a similar question up that I posted about moving into lambdas. C++0x doesn't have any move capture syntax. The only solution I could come up with was some kind of proxy function object.

template<typename T, typename F> class move_capture_proxy {
    T t;
    F f;
public:
    move_capture_proxy(T&& a, F&& b) 
        : t(std::move(a)), f(std::move(b)) {}
    auto operator()() -> decltype(f(std::move(b)) {
        return f(std::move(b));
    }
};
template<typename T, typename F> move_capture_proxy<T, F> make_move_proxy(T&& t, F&& f) {
    return move_capture_proxy<T, F>(std::move(t), std::move(f));
}

execution_queue.try_push(make_move_proxy(std::move(task), [](decltype(task)&& ref) {
    auto task = std::move(ref);
    // use task
});

Note that I haven't actually tried this code, and it would become a lot nicer with variadic templates, but MSVC10 doesn't have them so I don't really know about them.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文