У меня вопрос о реализации Coroutines TS в Visual Studio 2015. В рабочем документе P0057r5 говорится, что сопрограмма ведет себя так, как если бы его тело было:
{
P p;
auto gro = p.get_return_object();
co_await p.initial_suspend(); // initial suspend point
F’
final_suspend:
co_await p.final_suspend(); // final suspend point
}
(§ 8.4.4 \ 3) и что, когда сопрограмма возвращается к своей вызывающей стороне, возвращаемое значение создается, как если бы оператором return gro;
(§ 8.4.4 \ 5)
Обратите внимание, что результат p.get_return_object()
сохраняется в переменной с выведенным типом auto
.
Пусть тип возврата сопрограммы будет A
, а тип возврата promise.get_return_object()
будет B
. Согласно P0057r5, упомянутая выше переменная gro
должна иметь тип B
(выводится auto
), а объект типа A
должен быть построен из gro
, когда сопрограмма возвращается вызывающей стороне (например, с использованием оператора преобразования в B
или неявного конструктора из B
в A
).
В текущей реализации Visual Studio (строка версии компилятора: «Оптимизирующий компилятор Microsoft (R) C / C ++ версии 19.00.24215.1 для x86») преобразование выполняется после p.initial_suspend()
и до вызова F'
, как если бы тип gro
был установлен в соответствии с типом возврата сопрограмма (A
), а не тип возврата promise.get_return_object()
(B
).
Я что-то упустил или это ошибка?
Минимальный пример (компилируйте с / await):
#include <experimental/coroutine>
#include <iostream>
struct foo;
struct foo_builder {
foo_builder() {
std::cout << "foo_builder constructor\n";
}
operator foo();
};
struct foo_promise {
foo_builder get_return_object() {
return{};
}
void return_value(int value) {
std::cout << "co_return with " << value << "\n";
}
std::experimental::suspend_never initial_suspend() {
std::cout << "Initial suspend\n";
return{};
}
std::experimental::suspend_never final_suspend() {
return{};
}
};
struct foo {
foo() {
std::cout << "foo constructor\n";
}
using promise_type = foo_promise;
};
foo_builder::operator foo() {
std::cout << "foo_builder conversion to foo\n";
return{};
}
foo coroutine() {
co_return 5;
}
foo simple() {
foo_promise p;
auto gro = p.get_return_object();
// co_await p.initial_suspend(); // initial suspend point
// co_return 5;
p.return_value(5); //S;
goto final_suspend;
final_suspend:
// co_await p.final_suspend(); // final suspend point
return gro;
}
int main() {
auto v = coroutine();
std::cout << "\nregular function:\n";
auto v2 = simple();
std::cin.ignore();
}
Выход:
Initial suspend
foo_builder constructor
foo_builder conversion to foo
foo constructor
co_return with 5
regular function:
foo_builder constructor
co_return with 5
foo_builder conversion to foo
foo constructor