【发布时间】:2021-10-07 01:10:23
【问题描述】:
我创建了一个generator,它将有一个重载operator*,以便转换为std::ranges::subrange,我还想从promise_type 重载yield_value,它接受一个将产生的子范围类型递归。
源代码:
template <typename T>
class [[nodiscard]] generator {
public:
using value_type = T;
struct promise_type;
using handle_type = std::coroutine_handle<promise_type>;
private:
handle_type handle_ { nullptr };
explicit generator(handle_type handle) : handle_(handle) {}
public:
struct promise_type {
value_type value_;
generator<value_type> get_return_object() {
return generator{ handle_type::from_promise(*this) };
}
std::suspend_always initial_suspend() { return {}; }
std::suspend_always final_suspend() { return {}; }
void unhandled_exception() { std::terminate(); }
std::suspend_always yield_value(const value_type& value) noexcept {
value_ = value;
return {};
}
template <typename U>
std::suspend_never await_transform(U&&) = delete;
void return_void() {}
};
generator() noexcept = default;
generator(const generator&) = delete;
generator(generator&& other) noexcept
: handle_(std::move(other.handle_)) {
other.handle_ = nullptr;
}
~generator() { if (handle_) handle_.destroy(); }
generator& operator=(const generator&) = delete;
generator& operator=(generator&& other) noexcept {
handle_ = std::move(other.handle_);
other.handle_ = nullptr;
return *this;
}
void swap(generator& other) noexcept {
using std::swap;
swap(handle_, other.handle_);
}
class iterator {
private:
handle_type handle_;
friend generator;
explicit iterator(handle_type handle) noexcept
: handle_(handle) {}
public:
using value_type = std::remove_cvref_t<T>;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = value_type*;
using const_pointer = const value_type*;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using iterator_category = std::input_iterator_tag;
iterator() noexcept = default;
friend bool operator==(const iterator& iter, std::default_sentinel_t) noexcept {
return iter.handle_.done();
}
friend bool operator==(std::default_sentinel_t s, const iterator& iter) noexcept {
return (iter == s);
}
iterator& operator++() {
if (handle_.done()) handle_.promise().unhandled_exception();
handle_.resume();
return *this;
}
iterator operator++(int) {
auto temp = *this;
++*this;
return temp;
}
reference operator*() noexcept {
return handle_.promise().value_;
}
pointer operator->() noexcept {
return std::addressof(operator*());
}
};
iterator begin() noexcept {
if (handle_) {
handle_.resume();
if (handle_.done())
handle_.promise().unhandled_exception();
}
return iterator{handle_};
}
std::default_sentinel_t end() noexcept {
return std::default_sentinel;
}
};
例子:
auto generate_0(int n) -> generator<int> {
while (n != 0)
co_yield n--;
}
auto generate_1() -> generator<int> {
for (const auto& elem : generate_0(10)) {
co_yield elem;
}
}
generate_1 显然可以工作,但我希望有与 generate_1 一样的输出,每个元素都是 co_yield-ed 直接在 yield_value 内:
auto generate_1() -> generator<int> {
co_yield* generate_0(10);
}
这样:
在课堂generator:
auto operator*() {
return std::ranges::subrange(begin(), end());
}
在嵌套类generator<...>::promise_type:
template <typename U>
std::suspend_always yield_value(const std::ranges::subrange<U, std::default_sentinel_t>& r) noexcept {
/** ... **/
return {};
}
【问题讨论】:
标签: c++ generator c++-coroutine