packaged_task 中 lambda 的模板类型推导

问题描述 投票:0回答:1

尝试创建一个可以使用packaged_task执行任何作业的JobProcessor:

class JobProcessor
{
    public:
        JobProcessor(uint8_t numThreads = 8);

        template<class Fn, class... Args>
        auto add_task(JobPriority priority, Fn task, Args... args)
        {
            auto packaged_task = package_task(task, args...);
            {
                std::lock_guard<std::mutex> lk(_task_wait);
                _job_list.emplace(priority, std::move(packaged_task.first));
            }
            _task_sem.notify_one();
            return std::move(packaged_task.second);
        }
        
        virtual void run();
        virtual void stop() { _stop = false; };

    protected:
        template<class Fn, class... Args> requires std::invocable<Fn, Args...>
        auto package_task(Fn f, Args... args) const
        {
            using Ret = std::invoke_result_t<Fn, Args...>;

            // Create the packaged_task
            auto task = std::packaged_task<Ret()>(
                [f = std::move(f), ... captured_args = std::forward<Args>(args)]() mutable
                {
                    return std::invoke(std::move(f), std::move(captured_args)...);
                }
            );
            // Get the future before wrapping the task to be able to use the return
            auto future = task.get_future();

            // Wrap it in a lambda to the task can return any type
            auto task_wrapper = [task = std::move(task)]() mutable {
                task();
            };

            return std::make_pair(std::move(task_wrapper), std::move(future));
        }

    private:
        std::atomic_bool _stop;
        uint8_t _numThreads;
        std::list<std::thread> _threads;
        std::mutex _task_wait;
        std::condition_variable _task_sem;
        std::priority_queue<Job> _job_list;
};

工作声明为:

class Job
{
    public:
        Job(JobPriority priority, std::packaged_task<void()> task)
            : priority(priority), task(std::move(task)) 
        {}
        Job(const Job&) = delete;
        Job(Job&& job)
        {
            this->task = std::move(job.task);
            this->priority = job.priority;
        }

        int priority;

        void execute()
        {
            task();
        }

        friend bool operator<(const Job& lhs, const Job& rhs)
        {
            return lhs.priority < rhs.priority;
        }
    private:
        std::packaged_task<void()> task;
};

我希望这个处理器能够执行一个可以在未来返回某些内容的任务,因此我将 Job 打包到 lambda 中。 然而,当尝试像这样使用它时:

auto future1 = job_processor.add_task(JobPriority::LOW, [&]() {
        task1_executed = true;
    });

我收到以下错误:

note:   no known conversion for argument 2 from 'JobProcessor::package_task<JobProcessorTest_BasicExecution_Test::TestBody()::<lambda()> >(JobProcessorTest_BasicExecution_Test::TestBody()::<lambda()>) const::<lambda()>' to 'std::packaged_task<void()>'
   16 |         Job(JobPriority priority, std::packaged_task<void()> task)
      |                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~

lambda 签名应该是

void()

为什么编译器不能推断出这一点?我该如何解决它?

c++ templates lambda template-argument-deduction packaged-task
1个回答
0
投票

这里的问题主要是由

std::packaged_task
内部使用
operator=
引起的。声明复制和移动运算符解决了这个问题。

© www.soinside.com 2019 - 2024. All rights reserved.