@@ -476,16 +476,29 @@ class DPP_EXPORT cluster {
476476 * @return timer A handle to the timer, used to remove that timer later
477477 */
478478 template <std::invocable<timer> T, std::invocable<timer> U = std::function<void (timer)>>
479- requires (dpp::awaitable_type<typename std::invoke_result<T, timer>::type>)
479+ requires (
480+ dpp::awaitable_type<typename std::invoke_result<T, timer>::type> &&
481+ std::copy_constructible<std::decay_t <T>> && // N4988 [func.wrap.func.con]/10.1 - std::function requires a copy constructible argument
482+ std::copy_constructible<std::decay_t <U>>
483+ )
480484 timer start_timer(T&& on_tick, uint64_t frequency, U&& on_stop = {}) {
481- std::function<void (timer)> ticker = [fun = std::forward<T>(on_tick)](timer t) mutable -> dpp::job {
485+ using tick_fun = std::decay_t <T>;
486+ using stop_fun = std::decay_t <U>;
487+
488+ // We want to ship the function object on the coroutine frame to allow for lambda captures
489+ // See https://discord.com/channels/825407338755653642/825411707521728512/1495801839827030067
490+ // and https://discord.com/channels/825407338755653642/825411707521728512/1492502683444052109
491+ // Now we can only realistically do that by copying the lambda on each invocation, I think...
492+ // People should be avoiding lambda captures to begin with (see https://dpp.dev/coro-introduction.html),
493+ // so while this isn't super efficient, it's practically zero-cost with no capture anyways
494+ std::function<void (timer)> ticker = std::bind_front ([](tick_fun fun, timer t) -> dpp::job {
482495 co_await std::invoke (fun, t);
483- };
496+ }, static_cast <tick_fun>(std::forward<T>(on_tick))) ;
484497 std::function<void (timer)> stopper;
485498 if constexpr (dpp::awaitable_type<typename std::invoke_result<U, timer>::type>) {
486- stopper = [fun = std::forward<U>(on_stop)]( timer t) mutable -> dpp::job {
499+ stopper = std::bind_front ([](stop_fun fun, timer t) -> dpp::job {
487500 co_await std::invoke (fun, t);
488- };
501+ }, static_cast <stop_fun>(std::forward<U>(on_stop))) ;
489502 } else {
490503 stopper = std::forward<U>(on_stop);
491504 }
0 commit comments