Anton
Anton

Reputation: 305

How to return a value from a coroutine using co_return?

In the code below, I am trying to return from a coroutine std :: vector . The problem is that only the result of the std::vector<int> get_return_object() is returned from the coroutine.

When the co_return statement is executed, method void return_value(std::vector<int>&& value) is called, which fills the vector returned by method get_return_object(). But the vector from get_return_object() is returned by value and it doesn't work. When I try to do so

std::vector<int> return_value(std::vector<int>&& value){
    return value
}

An empty vector is also returned from the coroutine, although value is not empty.

How to return a value from a coroutine without wrapping it in a Task containing a promise_object?

exemple:

#include "coroutine"
#include "iostream"
struct Promise {
    std::vector<int> vec;
    std::vector<int> get_return_object() {
        return vec;
    }

    std::suspend_never initial_suspend() {
        return {};
    }

    std::suspend_never final_suspend() {
        return {};
    }

    void return_void() {}

    void return_value(std::vector<int>&& value){
        vec = std::move(value);
    }

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

template<typename... Args>
struct std::coroutine_traits<std::vector<int>, Args...>{
    using promise_type = Promise;
};

class Caller{
public:
    std::vector<int> call();
};

std::vector<int> Caller::call() {
    co_return std::vector<int>{1, 2, 3, 4};
}

int main(){
    Caller c;
    auto vec =  c.call();
    std::cout << vec.size();
    return 0;
}

Upvotes: 2

Views: 1897

Answers (1)

Caleth
Caleth

Reputation: 63152

std::vector<int> is not an awaitable type, so it can't usefully be the return object of a coroutine.

If you add some tracing, you can see the order of operations going wrong.

get_return_object needs to return something that can be given a std::vector<int> later. E.g. if all users of Promise never suspend:

struct Promise {
    struct result {
        std::future<std::vector<int>> fut;
        operator std::vector<int>() { return fut.get(); }
    };
    
    std::promise<std::vector<int>> prom;

    result get_return_object() {
        std::cout << "get_return_object" << std::endl;
        
        return { prom.get_future() };
    }

    std::suspend_never initial_suspend() {
        std::cout << "initial_suspend" << std::endl;
        return {};
    }

    std::suspend_never final_suspend() {
        std::cout << "final_suspend" << std::endl;
        return {};
    }

    void return_void() {}

    void return_value(std::vector<int>&& value){
        std::cout << "return_value" << std::endl;
        prom.set_value(std::move(value));
    }

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

Upvotes: 2

Related Questions