Я пытаюсь определить свой собственный тип обещания сопрограммы, и у меня есть следующие объявления:
void return_void() requires std::same_as {}
template
void return_value(X&& x) requires (!std::same_as) {}
Но компилятор жалуется, что я определил оба, несмотря на объявления require:
return.cpp: In function ‘Future b()’:
return.cpp:103:40: error: the coroutine promise type ‘std::__n4861::__coroutine_traits_impl::promise_type’ {aka ‘Future::promise_type’} declares both ‘return_value’ and ‘return_void’
103 | __attribute__((noinline)) Future b()
| ^
return.cpp:27:14: note: ‘return_void’ declared here
27 | void return_void() requires std::same_as {}
| ^~~~~~~~~~~
return.cpp:30:14: note: ‘return_value’ first declared here
30 | void return_value(X&& x) requires (!std::same_as) {}
| ^~~~~~~~~~~~
Разве смысл функции require не в том, чтобы иметь возможность выражать подобные перегрузки без трюков std::enable_if и выведенных типов?
Полный минимальный пример:
#include
#include
#include
#include
#include
template
class Future
{
public:
class Awaiter;
class promise_type {
private:
std::exception_ptr _exception;
std::coroutine_handle _continuation;
friend class Awaiter;
public:
Future 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 {}
template
void return_value(X&& x) requires (!std::same_as) {}
void unhandled_exception() {
_exception = std::current_exception();
}
};
operator bool() const
{
return _status == Status::Done || _status == Status::Exception;
}
struct Awaiter {
private:
Future& future;
public:
explicit Awaiter(Future& 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;
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 b()
{
co_return;
}
Подробнее здесь: https://stackoverflow.com/questions/793 ... -exclusive