查了一下,std::coroutine库没有实现默认的generator,我在github上面找了一个三方实现的std::generator。没咋看代码。但是能用。
主要就是使用协程实现递归。后根遍历二叉树。
代码结构如下,
苹果的clang 12.0.5没有完整实现协程库。所以会标红。
实际在fedora最新镜像中是可以编译通过的。
test/CMakeLists.txt
cmake_minimum_required(VERSION 2.6)
if(APPLE)
message(STATUS "This is Apple, do nothing.")
set(CMAKE_MACOSX_RPATH 1)
set(CMAKE_PREFIX_PATH /Users/aabjfzhu/software/vcpkg/ports/cppwork/vcpkg_installed/x64-osx/share )
elseif(UNIX)
message(STATUS "This is linux, set CMAKE_PREFIX_PATH.")
set(CMAKE_PREFIX_PATH /vcpkg/ports/cppwork/vcpkg_installed/x64-linux/share)
endif(APPLE)
project(binary_tree_it_coroutine)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-narrowing")
add_definitions(-g)
find_package(ZLIB)
find_package(OpenCV REQUIRED )
find_package(Arrow CONFIG REQUIRED)
find_package(unofficial-brotli REQUIRED)
find_package(unofficial-utf8proc CONFIG REQUIRED)
find_package(Thrift CONFIG REQUIRED)
find_package(glog REQUIRED)
find_package(OpenSSL REQUIRED)
find_package(Boost REQUIRED COMPONENTS
system
filesystem
serialization
program_options
thread
)
find_package(DataFrame REQUIRED)
if(APPLE)
MESSAGE(STATUS "This is APPLE, set INCLUDE_DIRS")
set(INCLUDE_DIRS ${Boost_INCLUDE_DIRS} /usr/local/include /usr/local/iODBC/include /opt/snowflake/snowflakeodbc/include/ ${CMAKE_CURRENT_SOURCE_DIR}/../include/ ${CMAKE_CURRENT_SOURCE_DIR}/../../../include)
elseif(UNIX)
MESSAGE(STATUS "This is linux, set INCLUDE_DIRS")
set(INCLUDE_DIRS ${Boost_INCLUDE_DIRS} /usr/local/include ${CMAKE_CURRENT_SOURCE_DIR}/../include/ ${CMAKE_CURRENT_SOURCE_DIR}/../../../include/)
endif(APPLE)
if(APPLE)
MESSAGE(STATUS "This is APPLE, set LINK_DIRS")
set(LINK_DIRS /usr/local/lib /usr/local/iODBC/lib /opt/snowflake/snowflakeodbc/lib/universal)
elseif(UNIX)
MESSAGE(STATUS "This is linux, set LINK_DIRS")
set(LINK_DIRS ${Boost_INCLUDE_DIRS} /usr/local/lib /vcpkg/ports/cppwork/vcpkg_installed/x64-linux/lib)
endif(APPLE)
if(APPLE)
MESSAGE(STATUS "This is APPLE, set ODBC_LIBS")
set(ODBC_LIBS iodbc iodbcinst)
elseif(UNIX)
MESSAGE(STATUS "This is linux, set LINK_DIRS")
set(ODBC_LIBS odbc odbcinst ltdl)
endif(APPLE)
include_directories(${INCLUDE_DIRS})
LINK_DIRECTORIES(${LINK_DIRS})
file( GLOB test_file_list ${CMAKE_CURRENT_SOURCE_DIR}>;
};
// Type-erased allocator with std::allocator_arg parameter (non-static member functions)
template
struct coroutine_traits, _This, allocator_arg_t, _Alloc, _Args...> {
private:
using __byte_allocator = __byte_allocator_t<_Alloc>;
public:
using promise_type = __generator_promise, __byte_allocator, true >;
};
// Generator with specified allocator type
template
struct coroutine_traits, _Args...> {
using __byte_allocator = __byte_allocator_t<_Alloc>;
public:
using promise_type = __generator_promise, __byte_allocator>;
};
// TODO : make layout compatible promise casts possible
template
class generator {
using __byte_allocator = __byte_allocator_t<_Alloc>;
public:
using promise_type = __generator_promise, __byte_allocator>;
friend promise_type;
private:
using __coroutine_handle = std::coroutine_handle;
public:
generator() noexcept = default;
generator(generator&& __other) noexcept
: __coro_(std::exchange(__other.__coro_, {}))
, __started_(std::exchange(__other.__started_, false)) {
}
~generator() noexcept {
if (__coro_) {
if (__started_ && !__coro_.done()) {
__coro_.promise().__value_.destruct();
}
__coro_.destroy();
}
}
generator& operator=(generator && g) noexcept {
swap(g);
return *this;
}
void swap(generator& __other) noexcept {
std::swap(__coro_, __other.__coro_);
std::swap(__started_, __other.__started_);
}
struct sentinel {};
class iterator {
public:
using iterator_category = std::input_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = _Value;
using reference = _Ref;
using pointer = std::add_pointer_t<_Ref>;
iterator() noexcept = default;
iterator(const iterator &) = delete;
iterator(iterator&& __other) noexcept
: __coro_(std::exchange(__other.__coro_, {})) {
}
iterator& operator=(iterator&& __other) {
std::swap(__coro_, __other.__coro_);
return *this;
}
~iterator() {
}
friend bool operator==(const iterator &it, sentinel) noexcept {
return it.__coro_.done();
}
iterator &operator++() {
__coro_.promise().__value_.destruct();
__coro_.promise().resume();
return *this;
}
void operator++(int) {
(void)operator++();
}
reference operator*() const noexcept {
return static_cast(__coro_.promise().__value_.get());
}
private:
friend generator;
explicit iterator(__coroutine_handle __coro) noexcept
: __coro_(__coro) {}
__coroutine_handle __coro_;
};
iterator begin() {
assert(__coro_);
assert(!__started_);
__started_ = true;
__coro_.resume();
return iterator{__coro_};
}
sentinel end() noexcept {
return {};
}
private:
explicit generator(__coroutine_handle __coro) noexcept
: __coro_(__coro) {
}
public: // to get around access restrictions for __yield_sequence_awaitable
std::coroutine_handle<> __get_coro() noexcept { return __coro_; }
promise_type* __get_promise() noexcept { return std::addressof(__coro_.promise()); }
private:
__coroutine_handle __coro_;
bool __started_ = false;
};
// Specialisation for type-erased allocator implementation.
template
class generator<_Ref, _Value, use_allocator_arg> {
using __promise_base = __generator_promise_base<_Ref>;
public:
generator() noexcept
: __promise_(nullptr)
, __coro_()
, __started_(false)
{}
generator(generator&& __other) noexcept
: __promise_(std::exchange(__other.__promise_, nullptr))
, __coro_(std::exchange(__other.__coro_, {}))
, __started_(std::exchange(__other.__started_, false)) {
}
~generator() noexcept {
if (__coro_) {
if (__started_ && !__coro_.done()) {
__promise_->__value_.destruct();
}
__coro_.destroy();
}
}
generator& operator=(generator g) noexcept {
swap(g);
return *this;
}
void swap(generator& __other) noexcept {
std::swap(__promise_, __other.__promise_);
std::swap(__coro_, __other.__coro_);
std::swap(__started_, __other.__started_);
}
struct sentinel {};
class iterator {
public:
using iterator_category = std::input_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = _Value;
using reference = _Ref;
using pointer = std::add_pointer_t<_Ref>;
iterator() noexcept = default;
iterator(const iterator &) = delete;
iterator(iterator&& __other) noexcept
: __promise_(std::exchange(__other.__promise_, nullptr))
, __coro_(std::exchange(__other.__coro_, {}))
{}
iterator& operator=(iterator&& __other) {
__promise_ = std::exchange(__other.__promise_, nullptr);
__coro_ = std::exchange(__other.__coro_, {});
return *this;
}
~iterator() = default;
friend bool operator==(const iterator &it, sentinel) noexcept {
return it.__coro_.done();
}
iterator& operator++() {
__promise_->__value_.destruct();
__promise_->resume();
return *this;
}
void operator++(int) {
(void)operator++();
}
reference operator*() const noexcept {
return static_cast(__promise_->__value_.get());
}
private:
friend generator;
explicit iterator(__promise_base* __promise, std::coroutine_handle<> __coro) noexcept
: __promise_(__promise)
, __coro_(__coro)
{}
__promise_base* __promise_;
std::coroutine_handle<> __coro_;
};
iterator begin() {
assert(__coro_);
assert(!__started_);
__started_ = true;
__coro_.resume();
return iterator{__promise_, __coro_};
}
sentinel end() noexcept {
return {};
}
private:
template
friend struct __generator_promise;
template
explicit generator(std::coroutine_handle<_Promise> __coro) noexcept
: __promise_(std::addressof(__coro.promise()))
, __coro_(__coro)
{}
public: // to get around access restrictions for __yield_sequence_awaitable
std::coroutine_handle<> __get_coro() noexcept { return __coro_; }
__promise_base* __get_promise() noexcept { return __promise_; }
private:
__promise_base* __promise_;
std::coroutine_handle<> __coro_;
bool __started_ = false;
};
#if __has_include()
namespace ranges {
template
constexpr inline bool enable_view> = true;
} // namespace ranges
#endif
} // namespace std
#endif // __STD_GENERATOR_INCLUDED
程序输出如下,



