C++ 如何在C++;20?

C++ 如何在C++;20?,c++,generator,c++20,C++,Generator,C++20,我只是一个简单的程序员,经常使用Python,并对其生成器上瘾。据我所知,它们可以在C++20中通过协同程序干净地实现,但是,至少在C++23之前,这不是一项简单的任务,因为需要编写生成器类(模板)。我怎么才能弄到那样的 跑得相当快(至少不比老款慢) 我可以为使用基于范围的、范围库和一些与Python的next等效的工具。如果能有一种方法来测试发电机是否耗尽,那也太好了 当(如果?)一个等价物被添加到标准库中时,我(很有可能)不需要对代码做太多更改 这可能吗?如评论中所述,提供了更高级别的抽象,

我只是一个简单的程序员,经常使用Python,并对其生成器上瘾。据我所知,它们可以在C++20中通过协同程序干净地实现,但是,至少在C++23之前,这不是一项简单的任务,因为需要编写生成器类(模板)。我怎么才能弄到那样的

  • 跑得相当快(至少不比老款慢)
  • 我可以为使用基于范围的
    、范围库和一些与Python的
    next
    等效的工具。如果能有一种方法来测试发电机是否耗尽,那也太好了
  • 当(如果?)一个等价物被添加到标准库中时,我(很有可能)不需要对代码做太多更改

  • 这可能吗?

    如评论中所述,提供了更高级别的抽象,可能会解决您的一些问题

    对于第2点,如果您真的需要一个公共方法来告诉您生成器已用尽,我想增强libcoro生成器会使它变得简单。这是一个(未测试)可能的样本。但是检查generator.end()对您来说是个问题吗

    namespace libcoro {
        template<typename T>
        class [[nodiscard]] generator
        {
        public:
    
        using reference_type = std::conditional_t<std::is_reference_v<T>, T, T&>;
    
        //.. libcoro stuff
    
        // ADDED
        bool done() const {
          m_coroutine.done();
        }
    
        reference_type value() const {
          return m_coroutine.promise().value();
        }
    
        void resume() {
          m_coroutine.resume();
        }
    
        // ...
    };
    
    名称空间libcoro{
    模板
    类[[nodiscard]]生成器
    {
    公众:
    使用reference\u type=std::conditional\u t;
    //…libcoro的东西
    //增加
    bool done()常量{
    m_corroute.done();
    }
    引用类型值()常量{
    返回m_coroutine.promise().value();
    }
    作废简历(){
    m_coroutine.resume();
    }
    // ...
    };
    
    }

    然后你可以做:

    while (true) {
            gen.resume();
            if(gen.done()) {
                std::cout << "this is the end!" << std::endl;
                break;
            }
            std::cout << "new value: " << gen.value() << std::endl;
    }
    
    while(true){
    一般恢复();
    如果(gen.done()){
    
    std::cout在这里,您可以找到一些相当快的生成器,如果可用的话,它更喜欢std实现(如在MSVC中):

    在我的真实代码中,它被分割成多个文件,但为了在这里显示它,我合并了它

    它适用于所有主要的喜剧演员(gcc、clang、msvc)

    //------------------
    //通用协同程序支持
    //------------------
    #如果已定义(_u-clang__;)
    //见:https://developercommunity.visualstudio.com/content/problem/502513/unable-to-use-clang-cl-coroutines-due-to-unresolve.html
    名称空间标准{
    名称空间实验{
    内联命名空间协同路由{
    模板
    结构协同程序{
    使用promise\u type=typename R::promise\u type;
    };
    模板
    结构协同程序句柄;
    模板结构协同程序句柄{
    来自地址(void*addr)的静态协程句柄无异常{
    与我共事;
    me.ptr=addr;
    还我;
    }
    void运算符()({resume();}
    void*address()常量{return ptr;}
    void resume()常量{{uuuuu内置的coro_uresume(ptr);}
    void destroy()常量{内置的coro destroy(ptr);}
    bool done()常量{return\u builtin\u coro\u done(ptr);}
    协同程序句柄和运算符=(decltype(nullptr)){
    ptr=nullptr;
    归还*这个;
    }
    协同程序句柄(decltype(nullptr)):ptr(nullptr){
    协同程序句柄():ptr(nullptr){}
    //void reset(){ptr=nullptr;}//是否添加到P0057?
    显式运算符bool()常量{return ptr;}
    受保护的:
    无效*ptr;
    };
    模板
    结构协同路由句柄:协同路由句柄{
    使用coroutine_handle::operator=;
    使用协同路由句柄::协同路由句柄;
    来自地址(void*addr)的静态协程句柄无异常{
    与我共事;
    me.ptr=addr;
    还我;
    }
    允诺&允诺()常量{
    返回*重新解释(
    __内建承诺(ptr、alignof(承诺)、false);
    }
    来自承诺(承诺与承诺)的静态协程句柄{
    协同程序;
    p、 ptr=uuu内置_uucoro_upromise(&promise,alignof(promise),true);
    返回p;
    }
    };
    模板
    布尔运算符==(协程句柄常量和左,
    协同程序(句柄常量和右)无例外
    {
    返回_Left.address()==_Right.address();
    }
    模板
    布尔运算符!=(协同程序句柄常量和左,
    协同程序(句柄常量和右)无例外
    {
    返回!(\u左==\u右);
    }
    结构挂起\u始终{
    bool wait_ready()noexcept{return false;}
    void wait_suspend(coroutine_handle)noexcept{}
    void wait_resume()无例外{}
    };
    结构挂起\u从不{
    bool wait_ready()noexcept{return true;}
    void wait_suspend(coroutine_handle)noexcept{}
    void wait_resume()无例外{}
    };
    }
    }
    }
    #定义本机协同程序实施标准::实验
    #elif有一个包含()
    #包括
    #定义本机协同程序执行标准
    #elif有一个包含()
    #包括
    #定义本机协同程序实施标准::实验
    #恩迪夫
    //------------------
    //发生器定义
    //-----------------
    #如果u_有u include()
    #包括
    名称空间核心\u本机\n
    {
    模板
    usi
    
    //------------------
    //general coroutine support
    //------------------
    #if defined(__clang__)
        //see: https://developercommunity.visualstudio.com/content/problem/502513/unable-to-use-clang-cl-coroutines-due-to-unresolve.html
        namespace std {
            namespace experimental {
                inline namespace coroutines_v1 {
    
                    template <typename R, typename...>
                    struct coroutine_traits {
                        using promise_type = typename R::promise_type;
                    };
    
                    template <typename Promise = void> 
                    struct coroutine_handle;
    
                    template <> struct coroutine_handle<void> {
                        static coroutine_handle from_address(void* addr) noexcept {
                            coroutine_handle me;
                            me.ptr = addr;
                            return me;
                        }
                        void operator()() { resume(); }
                        void* address() const { return ptr; }
                        void resume() const { __builtin_coro_resume(ptr); }
                        void destroy() const { __builtin_coro_destroy(ptr); }
                        bool done() const { return __builtin_coro_done(ptr); }
                        coroutine_handle& operator=(decltype(nullptr)) {
                            ptr = nullptr;
                            return *this;
                        }
                        coroutine_handle(decltype(nullptr)) : ptr(nullptr) {}
                        coroutine_handle() : ptr(nullptr) {}
                        //  void reset() { ptr = nullptr; } // add to P0057?
                        explicit operator bool() const { return ptr; }
    
                    protected:
                        void* ptr;
                    };
    
                    template <typename Promise> 
                    struct coroutine_handle : coroutine_handle<> {
                        using coroutine_handle<>::operator=;
                        using coroutine_handle<>::coroutine_handle;
    
                        static coroutine_handle from_address(void* addr) noexcept {
                            coroutine_handle me;
                            me.ptr = addr;
                            return me;
                        }
    
                        Promise& promise() const {
                            return *reinterpret_cast<Promise*>(
                                __builtin_coro_promise(ptr, alignof(Promise), false));
                        }
                        static coroutine_handle from_promise(Promise& promise) {
                            coroutine_handle p;
                            p.ptr = __builtin_coro_promise(&promise, alignof(Promise), true);
                            return p;
                        }
                    };
    
                    template <typename _PromiseT>
                    bool operator==(coroutine_handle<_PromiseT> const& _Left,
                        coroutine_handle<_PromiseT> const& _Right) noexcept
                    {
                        return _Left.address() == _Right.address();
                    }
    
                    template <typename _PromiseT>
                    bool operator!=(coroutine_handle<_PromiseT> const& _Left,
                        coroutine_handle<_PromiseT> const& _Right) noexcept
                    {
                        return !(_Left == _Right);
                    }
    
                    struct suspend_always {
                        bool await_ready() noexcept { return false; }
                        void await_suspend(coroutine_handle<>) noexcept {}
                        void await_resume() noexcept {}
                    };
                    struct suspend_never {
                        bool await_ready() noexcept { return true; }
                        void await_suspend(coroutine_handle<>) noexcept {}
                        void await_resume() noexcept {}
                    };
                }
            }
        }
        #define NATIVE_COROUTINE_IMPL_NS std::experimental
    #elif __has_include(<coroutine>)
        #include <coroutine>
        #define NATIVE_COROUTINE_IMPL_NS std    
    #elif __has_include(<experimental/coroutine>)
        #include <experimental/coroutine>
        #define NATIVE_COROUTINE_IMPL_NS std::experimental
    #endif
    
    //------------------
    //Generator defintion
    //-----------------
    
    #if __has_include(<generator>)
        #include <generator>
        namespace CORE_NATIVE_NS
        {
            template<typename T>
            using YieldEnum = std::generator<T>;
        }
    #elif __has_include(<experimental/generator>) && !defined(__clang__)
        #include <experimental/generator>
        namespace CORE_NATIVE_NS
        {
            template<typename T>
            using YieldEnum = std::experimental::generator<T>;
        }
    #else
    #include <memory>
    #include <cstddef>
    #include <type_traits>
    #include <utility>
    #include <exception>
    #include <iterator>
    #include <functional>
    
    namespace CORE_NATIVE_NS
    {
        template<typename T>
        class generator;
    
        namespace detail
        {
            template<typename T>
            class generator_promise
            {
            public:
                using value_type = std::remove_reference_t<T>;
                using reference_type = std::conditional_t<std::is_reference_v<T>, T, T&>;
                using pointer_type = value_type*;
    
                generator_promise() = default;
    
                generator<T> get_return_object() noexcept;
    
                constexpr NATIVE_COROUTINE_IMPL_NS::suspend_always initial_suspend() const noexcept 
                { return {}; }
                constexpr NATIVE_COROUTINE_IMPL_NS::suspend_always final_suspend() const noexcept
                { return {}; }
    
                template<
                    typename U = T,
                    std::enable_if_t<!std::is_rvalue_reference<U>::value, int> = 0
                >
                NATIVE_COROUTINE_IMPL_NS::suspend_always yield_value(std::remove_reference_t<T>& value) noexcept
                {
                    m_value = std::addressof(value);
                    return {};
                }
    
                NATIVE_COROUTINE_IMPL_NS::suspend_always yield_value(std::remove_reference_t<T>&& value) noexcept
                {
                    m_value = std::addressof(value);
                    return {};
                }
    
                void unhandled_exception() noexcept
                {
                    m_exception = std::current_exception();
                }
    
                void return_void() const noexcept
                {
                }
    
                reference_type value() const noexcept
                {
                    return static_cast<reference_type>(*m_value);
                }
    
                // Don't allow any use of 'co_await' inside the generator coroutine.
                template<typename U>
                NATIVE_COROUTINE_IMPL_NS::suspend_never await_transform(U&& value) = delete;
    
                void rethrow_if_exception()
                {
                    if (m_exception)
                    {
                        std::rethrow_exception(m_exception);
                    }
                }
            private:
                pointer_type m_value;
                std::exception_ptr m_exception;
            };
    
            struct generator_sentinel {};
    
            template<typename T>
            class generator_iterator
            {
                using coroutine_handle = NATIVE_COROUTINE_IMPL_NS::coroutine_handle<generator_promise<T>>;
            public:
    
                using iterator_category = std::input_iterator_tag;
                // What type should we use for counting elements of a potentially infinite sequence?
                using difference_type = std::ptrdiff_t;
                using value_type = typename generator_promise<T>::value_type;
                using reference = typename generator_promise<T>::reference_type;
                using pointer = typename generator_promise<T>::pointer_type;
    
                // Iterator needs to be default-constructible to satisfy the Range concept.
                generator_iterator() noexcept
                    : m_coroutine(nullptr)
                {}
    
                explicit generator_iterator(coroutine_handle coroutine) noexcept
                    : m_coroutine(coroutine)
                {}
    
                friend bool operator==(const generator_iterator& it, generator_sentinel) noexcept
                {
                    return !it.m_coroutine || it.m_coroutine.done();
                }
    
                friend bool operator!=(const generator_iterator& it, generator_sentinel s) noexcept
                {
                    return !(it == s);
                }
    
                friend bool operator==(generator_sentinel s, const generator_iterator& it) noexcept
                {
                    return (it == s);
                }
    
                friend bool operator!=(generator_sentinel s, const generator_iterator& it) noexcept
                {
                    return it != s;
                }
    
                generator_iterator& operator++()
                {
                    m_coroutine.resume();
                    if (m_coroutine.done())
                    {
                        m_coroutine.promise().rethrow_if_exception();
                    }
    
                    return *this;
                }
    
                // Need to provide post-increment operator to implement the 'Range' concept.
                void operator++(int)
                {
                    (void)operator++();
                }
    
                void next(){
                    (void)operator++();
                }
    
                reference operator*() const noexcept
                {
                    return m_coroutine.promise().value();
                }
    
                pointer operator->() const noexcept
                {
                    return std::addressof(operator*());
                }
    
            private:
                coroutine_handle m_coroutine;
            };
        }
    
        template<typename T>
        class [[nodiscard]] generator
        {
        public:
    
            using promise_type = detail::generator_promise<T>;
            using iterator = detail::generator_iterator<T>;
    
            generator() noexcept
                : m_coroutine(nullptr)
            {}
    
            generator(generator&& other) noexcept
                : m_coroutine(other.m_coroutine)
            {
                other.m_coroutine = nullptr;
            }
    
            generator(const generator& other) = delete;
    
            ~generator()
            {
                if (m_coroutine)
                {
                    m_coroutine.destroy();
                }
            }
    
            generator& operator=(generator other) noexcept
            {
                swap(other);
                return *this;
            }
    
            iterator begin()
            {
                if (m_coroutine)
                {
                    m_coroutine.resume();
                    if (m_coroutine.done())
                    {
                        m_coroutine.promise().rethrow_if_exception();
                    }
                }
    
                return iterator{ m_coroutine };
            }
    
            detail::generator_sentinel end() noexcept
            {
                return detail::generator_sentinel{};
            }
    
            void swap(generator& other) noexcept
            {
                std::swap(m_coroutine, other.m_coroutine);
            }
    
        private:
    
            friend class detail::generator_promise<T>;
    
            explicit generator(NATIVE_COROUTINE_IMPL_NS::coroutine_handle<promise_type> coroutine) noexcept
                : m_coroutine(coroutine)
            {}
    
            NATIVE_COROUTINE_IMPL_NS::coroutine_handle<promise_type> m_coroutine;
    
        };
    
        template<typename T>
        void swap(generator<T>& a, generator<T>& b)
        {
            a.swap(b);
        }
    
        namespace detail
        {
            template<typename T>
            generator<T> generator_promise<T>::get_return_object() noexcept
            {
                using coroutine_handle = NATIVE_COROUTINE_IMPL_NS::coroutine_handle<generator_promise<T>>;
                return generator<T>{ coroutine_handle::from_promise(*this) };
            }
        }
    
        template<typename FUNC, typename T>
        generator<std::invoke_result_t<FUNC&, typename generator<T>::iterator::reference>> fmap(FUNC func, generator<T> source)
        {
            for (auto&& value : source)
            {
                co_yield std::invoke(func, static_cast<decltype(value)>(value));
            }
        }
    
        template<typename T>
        using YieldEnum = CORE_NATIVE_NS::generator<T>;
    }
    #endif
    
    
    inline CORE_NATIVE_NS::YieldEnum<int> GetNumbers() noexcept
    {
        for(int i=0; i<= 10; ++i){
            co_yield 10;
        }
    }
    
    #include <iostream>
    
    int main()
    {
        int sum = 0;
        for(auto x : GetNumbers()){
            sum += x;
        }
        std::cout << sum;
        return 0;
    }