Как сказать Hello World с сопрограммой C ++ 20? - PullRequest
4 голосов
/ 17 мая 2019

Просто для учебы я попытался создать слишком сложную программу "Hello World" с сопрограммами на C ++ 20:

HelloWorldMessage sayHelloToWorld()
{
    co_yield "Hello";
    co_yield " ";
    co_yield "World";
    co_yield "!";
}

int main() 
{
    for (auto w : sayHelloToWorld())
    {
        std::cout << w;
    }
}

Чтобы подготовить такой генератор HelloWorldMessage, который я основывал в основном на последних предупреждающих сообщениях лязгаи неполная страница cppreference и этот пример .

Итак, мой результат ниже.Чего здесь не хватает?Потому что вместо того, чтобы сказать «Привет», я получил ошибку сегментации:

См. ссылка :

struct HelloWorldState
{
    const char* currentWord = "<not value yet>";
    bool finalWord = false;
};

struct HelloWorldPromise
{
    HelloWorldState state;
    std::experimental::suspend_always initial_suspend() const noexcept { return {}; }
    std::experimental::suspend_always final_suspend() const noexcept { return {}; }

    std::experimental::suspend_always yield_value(const char* word) noexcept
    {
        state.currentWord = word;
        return {};
    }  

    std::experimental::suspend_always return_void() noexcept
    {
        state.finalWord = true;
        return {};
    }  

    auto& get_return_object() noexcept
    {
        return *this;
    }

    void unhandled_exception()
    {
        state.finalWord = true;
        throw;
    }
};

struct HelloWorldMessage
{
    using promise_type = HelloWorldPromise;
    using promise_handle = std::experimental::coroutine_handle<promise_type>;

    struct Iter
    {
        promise_handle handle = nullptr;
        HelloWorldState state;

        using iterator_category = std::input_iterator_tag;
        using value_type        = const char*;
        using difference_type   = ptrdiff_t;
        using pointer           = value_type const *;
        using reference         = value_type const &;

        reference operator * () const { assert(handle); return state.currentWord; }
        pointer operator -> () const { return std::addressof(operator*()); }

        bool operator == (const Iter& other) { return handle == other.handle; }
        bool operator != (const Iter& other) { return !(*this == other); }

        Iter() = default;
        Iter(promise_handle handle)
            : handle(handle)
        {
           assert(handle);
           next();
        }

        Iter& operator ++()
        {
            if (!handle)
                return *this;
            if (state.finalWord)
            {
                handle = nullptr;
                return *this;
            }
            next();
            return *this;
        }

        void next()
        {
            try {
                handle.resume();
                state = handle.promise().state;
            } catch (...) {
                std::cerr << "@%$#@%#@$% \n";
            }
        }

    };

    promise_handle handle = nullptr;
    HelloWorldMessage(promise_type& promise) : handle(promise_handle::from_promise(promise)) {}

    Iter begin() const { assert(handle); return {handle}; }
    Iter end() const { return {}; }
};

Может быть, Clang еще не готов?

1 Ответ

1 голос
/ 17 мая 2019

Несколько ошибок:

Первое - обещание должно возвращать объект генератора, а не ссылку на самого себя. Итак, правильный путь:

struct HelloWorldPromise
{
    ...
    auto get_return_object();
    ...        
};

struct HelloWorldMessage
{
    ...
};

auto HelloWorldPromise::get_return_object()
{
    return HelloWorldMessage(*this);
}

Далее - прекращение и возврат void можно упростить до:

void return_void() noexcept
{}  
void unhandled_exception()
{
    std::terminate();
}

Далее - в итераторе - мы будем полагаться на handle.done - поэтому state.finalWord не нужен. Полный источник итератора:

struct Iter
{
    promise_handle handle = nullptr;
    HelloWorldState state;

    reference operator * () const { return state.currentWord; }
    pointer operator -> () const { return std::addressof(operator*()); }

    bool operator == (const Iter& other) { return !handle == !other.handle; }
    bool operator != (const Iter& other) { return !(*this == other); }

    Iter() = default;
    Iter(promise_handle handle)
        : handle(handle)
    {
       next();
    }

    Iter& operator ++()
    {
        if (!handle)
            return *this;
        next();
        return *this;
    }

    void next()
    {
        if (!handle)
            return;
        try {
            handle.resume();
            if (!handle.done())
               state = handle.promise().state;
            else {
                handle = nullptr;
            }
        } catch (...) {
            std::cerr << "@%$#@%#@$% \n";
        }
    }

};

И полный рабочий пример здесь .

Я беру большинство своих исправлений из этого 2018 / n4736.pdf .

...