Работает по указу. То есть он работает, потому что стандарт говорит , что он работает, и поэтому реализации должны найти способ реализации сопрограмм таким образом, чтобы это было возможно.
При создании сопрограммыРеализация создает две вещи: coroutine_handle и объект обещания. Расположение обеих этих вещей полностью контролируется компилятором. Таким образом, компилятор мог бы очень легко размещать их непрерывно друг с другом, так что стек сопрограммы по сути начинался бы с struct {coroutine_handle<Promise> handle; Promise promise};
.
Учитывая эти знания, вы знаете, что дескриптор для любого типа обещания живет sizeof(coroutine_handle<Promise>)
байт перед любым promise
адресом объекта (требования к выравниванию типа Promise
могут отрегулировать это, но такие вещи можно запросить из типа). А поскольку from_promise
принимает объект обещания, вы можете просто сместить указатель и привести его к coroutine_handle<Promise>
.
Теперь это только один из способов сделать это;реализация не должна делать это таким образом. Важно то, что реализация контролирует, где находится объект обещания относительно внутренних данных сопрограммы. Или, более конкретно, обещание живет внутри этих внутренних данных. Независимо от того, как вы смотрите на это, компилятор знает все, что ему нужно для того, чтобы преобразовать адрес обещания во внутренние данные, необходимые для заполнения coroutine_handle
.