简体   繁体   中英

Why can't VS2017 coroutines return void?

I was doing some experiments with the proposed c++ co-routines that are currently experimental in VS2017. I simply wanted to have a co-routine that doesn't return anything but calls co_await on some co-routine object that, let's say, does some processing on another thread before resuming. However, VS will not compile even the most rudimentary co-routine program that returns void. For instance:

#include "stdafx.h"
#include <experimental\coroutine>

using namespace std::experimental;

void bob()
{
    co_await suspend_always{};
}

int main()
{
    bob();
}

results in the errors:

1>c:\\program files (x86)\\microsoft visual studio\\2017\\professional\\vc\\tools\\msvc\\14.10.25017\\include\\experimental\\resumable(46): error C2825: '_Ret': must be a class or namespace when followed by '::' 1>d:\\dev\\coroutinestest\\main.cpp(10): note: see reference to class template instantiation 'std::experimental::coroutine_traits' being compiled 1>c:\\program files (x86)\\microsoft visual studio\\2017\\professional\\vc\\tools\\msvc\\14.10.25017\\include\\experimental\\resumable(46): error C2510: '_Ret': left of '::' must be a class/struct/union 1>c:\\program files (x86)\\microsoft visual studio\\2017\\professional\\vc\\tools\\msvc\\14.10.25017\\include\\experimental\\resumable(46): error C2061: syntax error: identifier 'promise_type' 1>c:\\program files (x86)\\microsoft visual studio\\2017\\professional\\vc\\tools\\msvc\\14.10.25017\\include\\experimental\\resumable(46): error C2238: unexpected token(s) preceding ';'

Now I assume that this error is due to void::promise_type being nonsensical, however why is the promise type even being instantiated when there's nothing to return? I would expect to be able to return nothing from a co-routine. Is this just a current bug in the implementation or am I misunderstanding the use of co-routines.

Thanks

Of course it CAN return void . The reason it doesn't is - no one implements the coroutine protocol for void . You can implement it on your own. The coroutine protocol for a return type is satisfied by providing a specialization for coroutine_traits .

To make void a valid return type for coroutines, you can do this:

namespace std::experimental
{
    template<class... T>
    struct coroutine_traits<void, T...>
    {
        struct promise_type
        {
            void get_return_object() {}

            void set_exception(exception_ptr const&) noexcept {}

            bool initial_suspend() noexcept
            {
                return false;
            }

            bool final_suspend() noexcept
            {
                return false;
            }

            void return_void() noexcept {}
        };
    };
}

This allows your example to compile.

However, note that in your example, calling co_await suspend_always{}; will cause memory leak, this is because coroutine_handle is much like a raw-pointer, and you're on your own to ensure the coroutine gets destroyed.

As a side note, the coroutine emulation library CO2 , however, takes another decision - its co2::coroutine has unique-ownership, so a call to CO2_AWAIT(suspend_always{}); won't leak memory, it just cancels the coroutine.

I stumbled across this question when trying to debug compiler error messages. The solution for me was to make the function return an IAsyncAction instead of returning void .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM