c++ - 将协程的返回设置为另一个协程内的变量会使编译器尝试转换承诺类型
问题描述
我目前遇到一个问题,我只是尝试 co_await 协程 B 将其返回保存到协程 A 内的变量中,但它尝试将 A 的承诺类型转换为 B 的承诺类型。
forStackoverflow.cpp: In function ‘myTask<std::optional<int> > getValue(std::vector<int>&, int, bool)’:
forStackoverflow.cpp:68:60: error: cannot convert ‘coroutine_handle<promise_type<std::optional<int>>>’ to ‘coroutine_handle<promise_type<int>>’
68 | leaf = co_await suspendableLocateValue(key, array, true);
| ^
forStackoverflow.cpp:42:58: note: initializing argument 1 of ‘void myTask<T>::await_suspend(std::__n4861::coroutine_handle<myTask<T>::promise_type>) const [with T = int]’
42 | void await_suspend(std::coroutine_handle<promise_type> coro) const noexcept { coro.promise().boolIsDone = true; }
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
#include <iostream>
#include <optional>
#include <utility>
#include <vector>
#include <concepts>
#include <coroutine>
#include <exception>
#include <iostream>
#include <vector>
template <typename T>
struct myTask {
struct promise_type {
T value_;
~promise_type() {}
myTask<T> get_return_object() {
return myTask<T> {
.h_ = std::coroutine_handle<promise_type>::from_promise(*this)
};
}
std::suspend_never initial_suspend() { return {}; }
std::suspend_always final_suspend()
{
boolIsDone = true;
return {};
}
void unhandled_exception() { std::terminate(); }
std::suspend_always return_value(auto value) {
value_ = value;
return {};
}
bool boolIsDone = false;
auto isDone() { return boolIsDone; }
};
bool await_ready() const noexcept { return false; }
void await_suspend(std::coroutine_handle<promise_type> coro) const noexcept { coro.promise().boolIsDone = true; }
void await_resume() const noexcept {}
std::coroutine_handle<promise_type> h_;
operator std::coroutine_handle<promise_type>() const { return h_; }
};
myTask<int> suspendableLocateValue(int key, std::vector<int>& array, bool interleave)
{
int currentInt = 0;
if (interleave = true)
{
//do something here
co_await std::suspend_always{};
}
currentInt = array.at(key);
co_return currentInt;
}
myTask<std::optional<int>> getValue(std::vector<int>& array, int key, bool interleave)
{
//int result = array.at(key);
int leaf;
if (interleave = true)
{
leaf = co_await suspendableLocateValue(key, array, true);
}
co_return std::make_optional(leaf);
}
void minimalInterleavedExecution(std::vector<int>& lookup,
std::vector<int>& keys,
std::vector<std::optional<int>>& results,
int groupsize)
{
std::vector<std::coroutine_handle<myTask<std::optional<int>>::promise_type>> handles;
for (int i = 0; i < groupsize; ++i)
{
handles.push_back(getValue(lookup, keys.at(i), true));
}
int notDone = groupsize;
int i = groupsize;
while (notDone > 0)
{
for (int handleIndex = 0; handleIndex < handles.size(); ++handleIndex)
{
if (!handles.at(handleIndex).promise().isDone())
{
handles.at(handleIndex).resume();
}
else
{
results.push_back(handles.at(handleIndex).promise().value_);
if (i < keys.size())
{
handles.at(handleIndex) = getValue(lookup, keys.at(i), true);
++i;
}
else
{
--notDone;
handles.erase(handles.begin() + handleIndex);
--handleIndex;
}
}
}
}
}
int main()
{
std::vector<int> lookup = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
std::vector<int> keys = {4, 2, 0, 6, 9, 0};
std::vector<std::optional<int>> results;
minimalInterleavedExecution(lookup, keys, results, 4);
}
我的原始代码实际上涉及一个 B+Tree 并且suspendableLocateValue
应该是一个函数,它查找并返回myTask<Node>
具有给定键的类型的叶子,并且getValue
应该将节点返回函数的返回值设置为新节点并获取特定的节点中的值以将其作为可选值返回。
解决方案
在返回值为的函数中myTask<std::optional<int>>
有一个调用
leaf = co_await suspendableLocateValue(key, array, true);
并suspendableLocateValue
返回myTask<int>
。但是await_suspend
没有模板化,因此不能使用:
void await_suspend(std::coroutine_handle<promise_type> coro) const noexcept
所以myTask<U>
只能在myTask<U>
协程中等待。
当co_await something
在协程中遇到时,编译器会执行几个步骤来确定该表达式的含义:
- 是否有
await_transform
封闭协程? - 有
operator co_await
吗?
否则(您的情况)它会生成具有something.await_suspend(h)
,其中h
astd::coroutine_handle<P>
和 P 是封闭协程承诺的类型的代码。
在您的示例中:
something
是myTask<int>
h
是std::coroutine_handle<myTask<std::optional<int>>::promise_type>
所以有一个电话,myTask<int>::await_suspend(std::coroutine_handle<myTask<std::optional<int>>::promise_type>)
但没有这样的功能。编译器尝试转换std::coroutine_handle<myTask<std::optional<int>>::promise_type>
为await_suspend
( std::coroutine_handle<myTask<int>::promise_type>
) 的实际参数类型并写入有关它的错误。
推荐阅读
- java - 动态报告导出pdf类未找到异常错误
- python - 如何获取来自数组的选定数字的坐标
- php - 递归数组列表类别
- c - C 代码只能在一个项目中工作,不能在任何新项目中工作(不会写 txt 文件)
- javascript - 在 JavaScript 中创建对象数组的所有组合
- swift - 更改 ViewController 后计数器重置为零
- c# - C# SerialPort.Write()方法的误解
- c++ - 为什么在编译 makefile 时出现“错误 1181”?
- java - Spring Boot 注释和导入无法在 Intellij IDE 上解析
- generics - Serde_json 使用泛型序列化 to_string