Technology1 min read

How can I make it easier to use the helper class that lets me pass more than one parameter to co_await?

By · Published by Everything Blog

In short

Manually merging inputs into composite structures for `co_await` operations quickly becomes cumbersome for developers to manage across a codebase. Providing a helper method automatically packages parameters and enables callers to invoke operations using straightforward syntax with optional default values. The class can also be configured so that awaiting an instance directly triggers a start with standard priority settings. Code duplication is kept to a minimum by utilizing `operator co_await` to return a versatile awaiter type.

Key points

  • Using helper methods such as `start()` substantially streamlines the syntax needed to sup…: Using helper methods such as `start()` substantially streamlines the syntax needed to supply parameters to coroutine awaitables.
  • Direct object awaiting can be designed to automatically fall back to execution using stan…: Direct object awaiting can be designed to automatically fall back to execution using standard default priority settings.
  • Standardizing awaitable method names and relying on `operator co_await` significantly cur…: Standardizing awaitable method names and relying on `operator co_await` significantly curtails redundant internal code.

Sources checked by our analysis pipeline: 1

Last time, we figured out how to pass more than one parameter to co_await

by combining the multiple parameter into a single mega-parameter.

But having to name the mega-parameter is annoying. Sure, today we have widget_

, and then we get gadget_

, and then doodad_

, and oh my goodness it’s out of control.

Instead of making the caller have to name the mega-parameter, we can create a helper method that produces it.

struct Widget { ⟦ ... other stuff ... ⟧ private: bool inner_await_ready() const { return ⟦ ... ⟧; } bool inner_await_suspend(std::coroutine_handle<> handle, int priority) { return internal_start(handle, priority); } auto inner_await_resume() const { return ⟦ ... ⟧; } struct with_priority { with_priority(Widget const& widget, int priority) : m_widget(widget), m_priority(priority) {} bool await_ready() const { return m_widget.inner_await_ready(); } auto await_suspend(std::coroutine_handle<> handle) { return m_widget.inner_await_suspend(handle, m_priority); } auto await_ready() { return m_widget.await_ready(); } Widget const& m_widget; int m_priority; }; public: with_priority start(int priority = 0) { return with_priority(*this, priority); } };

Now callers can write

co_await widget.start(priority);

As a convenience, I gave the start()

method a default priority,…

Technology