向WorkerQueue转发参数时出现编译错误,求扩展支持带参任务方案
Hey there! Let's fix that WorkerQueue to handle tasks with parameters. The core issue with your current implementation is that it only accepts parameterless callables, but we can use C++ variadic templates and perfect forwarding to make it work with any task and its arguments.
First, let's adjust the submit method to accept a callable and any number of arguments. We'll wrap the task and its arguments into a parameterless function object that the worker threads can execute. Here's the updated WorkerQueue implementation (core parts included, assuming your original code has a thread pool and task queue):
#include <iostream> #include <vector> #include <queue> #include <thread> #include <mutex> #include <condition_variable> #include <functional> #include <future> class WorkerQueue { private: std::vector<std::thread> workers; std::queue<std::function<void()>> tasks; std::mutex queue_mutex; std::condition_variable condition; bool stop = false; void worker_thread() { while (true) { std::function<void()> task; { std::unique_lock<std::mutex> lock(queue_mutex); condition.wait(lock, [this] { return stop || !tasks.empty(); }); if (stop && tasks.empty()) return; task = std::move(tasks.front()); tasks.pop(); } task(); } } public: WorkerQueue(size_t num_threads = std::thread::hardware_concurrency()) { for (size_t i = 0; i < num_threads; ++i) workers.emplace_back(&WorkerQueue::worker_thread, this); } ~WorkerQueue() { { std::unique_lock<std::mutex> lock(queue_mutex); stop = true; } condition.notify_all(); for (std::thread& worker : workers) worker.join(); } // Updated submit method with variadic templates template<class F, class... Args> void submit(F&& f, Args&&... args) { // Wrap function + args into a parameterless callable auto task = std::bind(std::forward<F>(f), std::forward<Args>(args)...); { std::unique_lock<std::mutex> lock(queue_mutex); tasks.emplace(std::move(task)); } condition.notify_one(); } // Optional: Version to get a future for task return values template<class F, class... Args> auto submit_with_future(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type> { using return_type = typename std::result_of<F(Args...)>::type; auto task = std::make_shared<std::packaged_task<return_type()>>( std::bind(std::forward<F>(f), std::forward<Args>(args)...) ); std::future<return_type> res = task->get_future(); { std::unique_lock<std::mutex> lock(queue_mutex); tasks.emplace([task]() { (*task)(); }); } condition.notify_one(); return res; } void wait_for_completion() { std::unique_lock<std::mutex> lock(queue_mutex); condition.wait(lock, [this] { return tasks.empty(); }); } };
Why This Works
- Variadic Templates: The
submitmethod usestemplate<class F, class... Args>to accept any callable and any number/type of arguments. - Perfect Forwarding:
std::forwardpreserves the value category (lvalue/rvalue) of inputs, avoiding unnecessary copies of temporary values. - Task Wrapping:
std::bindpackages the function and its arguments into astd::function<void()>that fits our existing task queue. - Optional Future Support: The
submit_with_futuremethod lets you retrieve return values from tasks, which is useful for result-producing work.
Test Example (Your Desired Usage)
Now your intended code will compile and run correctly:
int main() { WorkerQueue q; // Original parameterless task auto job1 = [](){ std::cout << "yay\n"; }; q.submit(job1); // Task with single parameter auto job2 = [](int yay) { std::cout << yay << '\n'; }; q.submit(job2, 42); // Pass arguments directly // Task with multiple parameters auto job3 = [](std::string msg, double num) { std::cout << msg << ": " << num << '\n'; }; q.submit(job3, "Pi approximation", 3.14159); // Task with return value (using future) auto job4 = [](int a, int b) { return a + b; }; auto sum_future = q.submit_with_future(job4, 10, 20); std::cout << "Sum: " << sum_future.get() << '\n'; q.wait_for_completion(); return 0; }
Common Compilation Error Fixes
The errors you likely hit were:
- Mismatched Signatures: Your original
submitexpected astd::function<void()>, but you passed a callable with parameters. The variadic template fixes this by wrapping the task into a parameterless object. - Missing Forwarding: Without
std::forward, temporary values (like literals or short-lived objects) might not be handled correctly, leading to copy errors. - Thread Safety Gaps: Always protect queue access with a mutex and use condition variables to wake workers when new tasks arrive.
内容的提问来源于stack exchange,提问作者codie

