C++-coroutines协程 将自定义类型转为awaitable(可等待)类型的两种方法

文章目录

  • 前言
  • 重载operator co_await
  • 定义promise_type::await_transform函数

前言

阅读本篇文章时,已经假定你有对协程的基本概念,如果没有,可以阅读我写的这篇协程入门文章

我们已经知道,对于co_await \,expression的返回值必须是awaitable类型,即正确实现了如下三个函数:

  • await_ready
  • await_suspend
  • await_resume
    对于返回值类型非awaitable的情况,我们有两种将自定义类型转为awaitable类型的方法:
  1. 重载operator co_await()
  2. 定义promise_type::await_transform函数

重载operator co_await

如果我们的返回值类型方便我们修改源代码,那么可以在类型中重载operator co_await,将该类型转为awaitable类型:

class MyClass {
public:
    std::suspend_always operator co_await() {
        return {};
    }
};
...
TaskPromise task_func()
{
    std::cout << "task first run" << std::endl;
    co_await MyClass();  // 这里会调用MyClass::operator co_await方法
    std::cout << "task resume" << std::endl;
}

这里重载的方法和普通的运算符重载的原理完全相同。事实上,我们也可以在外部定义operator co_await函数:

std::suspend_always operator co_await(const MyClass&) {
    return {};
}

定义promise_type::await_transform函数

对于协程而言,这种方法的调用优先级比前一种方法高,编译器会先查找promist_type中是否定义了await_transform函数,如果有,则直接调用该函数,不会调用operator co_await;如果没有,则查找operator co_await函数并调用。

struct TaskPromise
{
    struct promise_type
    {
    	// ...
        std::suspend_always await_transform(MyClass&& obj) {
            return {};
        }
    };

通过上面两种方法,我们就能co_await等待任意类型。例如qcoro库中有如下代码:

QCoro::Task<> start() {
    mPb->setVisible(true);
    mBtn->setEnabled(false);
    mBtn->setText(tr("Downloading ..."));

    std::unique_ptr<QNetworkReply> reply(co_await mNam.get(QNetworkRequest{wikiUrl}));  // 这里通过await_transform发生了上面所说的转换!
    if (reply->error()) {
        QMessageBox::warning(
            this, tr("Network request error"),
            tr("Error occured during network request. Error code: %1").arg(reply->error()));
        co_return;
    }

    mPb->setVisible(false);
    mBtn->setEnabled(true);
    mBtn->setText(tr("Done, download again"));
}

你可能感兴趣的:(#,Coroutines,c++,开发语言,协程,coroutines)