Quantcast
Channel: Active questions tagged require - Stack Overflow
Viewing all articles
Browse latest Browse all 144

Why can't C++ tell return_void and return_value are mutually exclusive?

$
0
0

I am trying to define my own coroutine promise type, and I have the following declarations:

void return_void() requires std::same_as<T, void> {}template<class X>void return_value(X&& x) requires (!std::same_as<T, void>) {}

But, the compiler complains that I have defined both, despite the requires declarations:

return.cpp: In function ‘Future<void> b()’:return.cpp:103:40: error: the coroutine promise type ‘std::__n4861::__coroutine_traits_impl<Future<void>, void>::promise_type’ {aka ‘Future<void>::promise_type’} declares both ‘return_value’ and ‘return_void’  103 | __attribute__((noinline)) Future<void> b()      |                                        ^return.cpp:27:14: note: ‘return_void’ declared here   27 |         void return_void() requires std::same_as<T, void> {}      |              ^~~~~~~~~~~return.cpp:30:14: note: ‘return_value’ first declared here   30 |         void return_value(X&& x) requires (!std::same_as<T, void>) {}      |              ^~~~~~~~~~~~

Isn't the point of the requires feature to be able to express overloads like this without std::enable_if trickery and inferred types?

Full minimal example:

#include <concepts>#include <coroutine>#include <exception>#include <iostream>#include <vector>template<class T>class Future{public:    class Awaiter;    class promise_type {    private:        std::exception_ptr _exception;        std::coroutine_handle<> _continuation;        friend class Awaiter;    public:        Future<T> get_return_object() { return {HandleT::from_promise(*this)}; }        std::suspend_always initial_suspend() { return {}; }        std::suspend_never final_suspend() noexcept { return {}; }        void return_void() requires std::same_as<T, void> {}        template<class X>        void return_value(X&& x) requires (!std::same_as<T, void>) {}        void unhandled_exception() {            _exception = std::current_exception();        }    };    operator bool() const    {        return _status == Status::Done || _status == Status::Exception;    }    struct Awaiter {    private:        Future<T>& future;    public:        explicit Awaiter(Future<T>& future)            : future(future)        {}        // this will check if the future is already done, e.g. if it        // was `co_await`ed previously        bool await_ready() const noexcept { return bool(future); }        // this coroutine is the one doing the `co_await`        std::coroutine_handle<> await_suspend(std::coroutine_handle<> handle) noexcept        {            // remember we want to resume back intot his caller later            future._handle.promise()._continuation = handle;            // For now let the coroutine associated with this future            // run, via "symmetric transfer", which takes the caller            // resume call off the stack and replaces it with this            // coroutine.            return future._handle;        }        void await_resume() const noexcept        {        }    };    auto operator co_await() {        return Awaiter(*this);    }    void resume() {        _handle.resume();    }protected:    using HandleT = std::coroutine_handle<promise_type>;    Future(HandleT&& p)        : _handle(std::move(p))    {}    Future(const Future&) = delete;    Future& operator=(const Future&) = delete;    friend class Awaiter;    enum class Status {        Unfinished,        Done,        Exception,        Empty    } _status = Status::Unfinished;    HandleT _handle;    std::exception_ptr _exception = nullptr;};Future<void> b(){    co_return;}

Viewing all articles
Browse latest Browse all 144

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>