mr-element 2023-11-29 20:34 采纳率: 60%
浏览 26
已结题

C++代码报错问题,c++20协程

c++代码报错,我想实现一个可以递归的generator,不能修改main.cpp文件的内容,只能修改sleep.h和generator.h文件的内容。
我的编译方法为g++-10 -std=c++20 -fcoroutines -o main main.cpp
目前代码报错:

main.cpp: In functioncoro::generator<int> range(int, int)’:
main.cpp:11:23: error: cannot convertcoro::generator<int>’ toint’
   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 functioncoro::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 functionint main()’:
main.cpp:27:23: error: too few arguments to functioncoro::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();
}

  • 写回答

11条回答 默认 最新

  • 梦回阑珊 2023-11-30 15:39
    关注

    回复不易,麻烦关注下博主,后面还有问题直接私信我,谢谢!!!

    在你的 range 函数中,co_yield range(start + 1, end); 行导致了错误。在这里,你试图 co_yield 另一个生成器,但是你的 range 函数应该返回一个 int 类型的值,而不是生成器本身。

    为了实现递归的生成器,你可以使用一个内部函数(helper function)来实现递归调用。以下是你的代码的修复版本:

    在 generator.h 中修改 promise_type 的 yield_value 函数,使其支持生成器类型:

    std::suspend_always yield_value(const generator& gen) {
        value = gen;
        return {};
    }
    
    
    

    然后,将 range 函数修改如下:

    coro::generator<int> range(int start, int end) {
        co_yield start;
        if (start + 1 < end) {
            co_yield range(start + 1, end);
        }
    }
    
    
    

    这样,你的 range 函数会正确返回 int 类型的值。在递归调用时,co_yield range(start + 1, end); 会调用 yield_value 函数,该函数已经被修改以支持生成器类型。

    请注意,由于 range 函数返回 int 类型,对 co_yield range(start + 1, end); 的调用实际上是对 yield_value 函数的调用,而不是递归调用 range 函数。

    这样修改后,你的代码应该能够成功编译并运行。

    评论

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 12月4日
  • 创建了问题 11月29日

悬赏问题

  • ¥15 数学建模招标中位数问题
  • ¥15 phython路径名过长报错 不知道什么问题
  • ¥15 深度学习中模型转换该怎么实现
  • ¥15 HLs设计手写数字识别程序编译通不过
  • ¥15 Stata外部命令安装问题求帮助!
  • ¥15 从键盘随机输入A-H中的一串字符串,用七段数码管方法进行绘制。提交代码及运行截图。
  • ¥15 TYPCE母转母,插入认方向
  • ¥15 如何用python向钉钉机器人发送可以放大的图片?
  • ¥15 matlab(相关搜索:紧聚焦)
  • ¥15 基于51单片机的厨房煤气泄露检测报警系统设计