c++代码报错,我想实现一个可以递归的generator,不能修改main.cpp文件的内容,只能修改sleep.h和generator.h文件的内容。
我的编译方法为g++-10 -std=c++20 -fcoroutines -o main main.cpp
目前代码报错:
main.cpp: In function ‘coro::generator<int> range(int, int)’:
main.cpp:11:23: error: cannot convert ‘coro::generator<int>’ to ‘int’
11 | co_yield range(start + 1, end);
| ~~~~~^~~~~~~~~~~~~~~~
| |
| coro::generator<int>
In file included from main.cpp:5:
generator.h:27:43: note: initializing argument 1 of ‘std::__n4861::suspend_always coro::generator<T>::promise_type::yield_value(T) [with T = int]’
27 | std::suspend_always yield_value(T v) {
| ~~^
main.cpp: In lambda function:
main.cpp:21:5: error: use of deleted function ‘coro::generator<const char>::promise_type::promise_type()’
21 | }();
| ^
In file included from main.cpp:5:
generator.h:16:12: note: ‘coro::generator<const char>::promise_type::promise_type()’ is implicitly deleted because the default definition would be ill-formed:
16 | struct promise_type {
| ^~~~~~~~~~~~
generator.h:16:12: error: uninitialized const member in ‘struct coro::generator<const char>::promise_type’
generator.h:17:11: note: ‘const char coro::generator<const char>::promise_type::value’ should be initialized
17 | T value;
| ^~~~~
main.cpp: In function ‘int main()’:
main.cpp:27:23: error: too few arguments to function ‘coro::generator<int> range(int, int)’
27 | auto gen = range(0);
| ^
main.cpp:8:22: note: declared here
8 | coro::generator<int> range(int start, int end) {
| ^~~~~
In file included from main.cpp:5:
generator.h: In instantiation of ‘std::__n4861::suspend_always coro::generator<T>::promise_type::yield_value(T) [with T = const char]’:
main.cpp:19:22: required from here
generator.h:28:19: error: assignment of read-only member ‘coro::generator<const char>::promise_type::value’
28 | value = v;
| ~~~~~~^~~
generator.h: In instantiation of ‘coro::generator<T>::iterator coro::generator<T>::begin() [with T = const char]’:
main.cpp:23:26: required from here
generator.h:78:32: error: ‘struct coro::generator<const char>::promise_type’ has no member named ‘rethrow_if_exception’
78 | coro.promise().rethrow_if_exception();
| ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~
generator.h: In instantiation of ‘coro::generator<T>::iterator& coro::generator<T>::iterator::operator++() [with T = const char]’:
main.cpp:23:26: required from here
generator.h:48:51: error: ‘struct coro::generator<const char>::promise_type’ has no member named ‘rethrow_if_exception’
48 | std::exchange(coro, {}).promise().rethrow_if_exception();
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~
generator.h文件内容为:
// generator.h
#pragma once
#include <coroutine>
#include <exception>
#include <iterator>
#include <utility>
namespace coro {
template <typename T>
class generator {
public:
struct promise_type;
using handle_type = std::coroutine_handle<promise_type>;
struct promise_type {
T value;
std::exception_ptr exception;
generator get_return_object() {
return generator(handle_type::from_promise(*this));
}
std::suspend_always initial_suspend() { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
void unhandled_exception() { exception = std::current_exception(); }
std::suspend_always yield_value(T v) {
value = v;
return {};
}
void return_void() {}
};
class iterator {
public:
using iterator_category = std::input_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = T;
using reference = const T&;
using pointer = const T*;
iterator() noexcept : coro(nullptr) {}
explicit iterator(handle_type coro) noexcept : coro(coro) {}
iterator& operator++() {
coro.resume();
if (coro.done()) {
std::exchange(coro, {}).promise().rethrow_if_exception();
}
return *this;
}
iterator operator++(int) {
iterator temp = *this;
++*this;
return temp;
}
bool operator==(const iterator& other) const {
return coro == other.coro;
}
bool operator!=(const iterator& other) const {
return coro != other.coro;
}
reference operator*() const noexcept {
return coro.promise().value;
}
pointer operator->() const noexcept {
return std::addressof(coro.promise().value);
}
private:
handle_type coro;
};
iterator begin() {
if (coro) {
coro.resume();
if (coro.done()) {
coro.promise().rethrow_if_exception();
return end();
}
}
return iterator(coro);
}
iterator end() noexcept {
return iterator();
}
generator() noexcept : coro(nullptr) {}
generator(generator&& other) noexcept : coro(std::exchange(other.coro, {})) {}
generator(const generator&) = delete;
~generator() {
if (coro) {
coro.destroy();
}
}
generator& operator=(generator other) noexcept {
std::swap(coro, other.coro);
return *this;
}
private:
explicit generator(handle_type h) noexcept : coro(h) {}
handle_type coro;
};
} // namespace coro
sleep.h文件内容为:
#include <coroutine>
#include <functional>
#include <queue>
#include <thread>
#include <chrono>
namespace coro {
static std::queue<std::function<void()>> task_queue;
struct sleep {
sleep(int n_ms) : delay{n_ms} {}
std::chrono::milliseconds delay;
bool await_ready() const noexcept { return delay.count() <= 0; }
void await_suspend(std::coroutine_handle<> handle) {
task_queue.push([this, handle]() {
std::this_thread::sleep_for(delay);
handle.resume();
});
}
void await_resume() noexcept {}
};
struct Task {
struct promise_type {
Task get_return_object() { return {}; }
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() { std::terminate(); }
};
};
void wait_task_queue_empty() {
while (!task_queue.empty()) {
auto task = std::move(task_queue.front());
task_queue.pop();
task();
}
}
} // namespace coro
main.cpp文件内容为:
#include <cassert>
#include <iostream>
#include <ranges>
#include "generator.h"
#include "sleep.h"
coro::generator<int> range(int start, int end) {
co_yield start;
if (start + 1 < end) {
co_yield range(start + 1, end);
}
}
int main() {
auto coro = []() -> coro::generator<const char> {
static const char str[] = "Start libco_v5 test\n";
for (const auto& c : str) {
co_yield c;
}
}();
for (const auto& c : coro) {
std::cout << c;
}
auto gen = range(0);
int ans = 0;
for (const auto& i : gen | std::views::filter([](int i) { return i % 2 == 0; }) | std::views::take(10)) {
assert(i == ans);
ans += 2;
}
assert(ans == 20);
auto task = []() -> coro::Task {
static const char str[] = "lbov akts asd\n";
for (const auto& c : str) {
co_await coro::sleep{300};
std::cout << c << std::flush;
}
}();
// libco_v5 task test passed!\n
// l b o v a k t s a s d \n
// i c _ 5 t s e t p s e !
auto task2 = []() -> coro::Task {
static const char str[] = "ic_5ts etpse!";
for (const auto& c : str) {
co_await coro::sleep{305};
std::cout << c << std::flush;
}
}();
coro::wait_task_queue_empty();
}