Also, some thoughts about this function:
- It should accept more types, not only a vector of callables. We don’t know what the caller is using std::array/std::vector/std::list (or any other container with a range).
- It should reject L-values. The caller must std::move the container so they are not copying it.
A patch that allows both points:
0diff --git a/src/util/threadpool.h b/src/util/threadpool.h
1--- a/src/util/threadpool.h
2+++ b/src/util/threadpool.h
3@@ -164,7 +164,10 @@
4 * uncaught exceptions, as they would otherwise be silently discarded.
5 */
6 template <class F>
7- [[nodiscard]] util::Expected<std::future<std::invoke_result_t<F>>, SubmitError> Submit(F&& fn) noexcept EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
8+ using Future = std::future<std::invoke_result_t<F>>;
9+
10+ template <class F>
11+ [[nodiscard]] util::Expected<Future<F>, SubmitError> Submit(F&& fn) noexcept EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
12 {
13 std::packaged_task<std::invoke_result_t<F>()> task{std::forward<F>(fn)};
14 auto future{task.get_future()};
15@@ -200,11 +203,13 @@
16 * [@warning](/bitcoin-bitcoin/contributor/warning/) Ignoring the returned futures requires guarding tasks against
17 * uncaught exceptions, as they would otherwise be silently discarded.
18 */
19- template <class F>
20- [[nodiscard]] util::Expected<std::vector<std::future<std::invoke_result_t<F>>>, SubmitError> SubmitMany(std::vector<F>&& fns) noexcept EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
21+ template <class F> using RangeValue = Future<std::ranges::range_value_t<F>>;
22+
23+ template <std::ranges::sized_range R>
24+ requires (!std::is_lvalue_reference_v<R>) // Reject l-values; caller must explicitly std::move the range
25+ [[nodiscard]] util::Expected<std::vector<RangeValue<R>>, SubmitError> SubmitMany(R&& fns) noexcept EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
26 {
27- using Result = std::invoke_result_t<F&>;
28- std::vector<std::future<Result>> futures;
29+ std::vector<RangeValue<R>> futures;
30 futures.reserve(fns.size());
31
32 {
It would also be nice to expand submit_many_tasks_complete_successfully to use a different container, just to exercise the change. Could use std::array or std::list.