визуальные сопрограммы VS2015 C ++: обещание.get_return_object () тип возвращаемого значения и тип возвращаемого сопрограммы

У меня вопрос по поводу реализации 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 ++ Optimizing Compiler Version 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

1

Решение

Получение возвращаемого значения get_return_object() от auto gro был добавлен в p0057r5. В предыдущей редакции (p0057r4) эта часть читается как

…сопрограмма ведет себя так, как если бы ее тело было:

{
P p ;
co_await p .initial_suspend(); // initial suspend point
F’
final_suspend :
co_await p .final_suspend(); // final suspend point
}

а также

Когда сопрограмма возвращается к своему вызывающему, возвращаемое значение получается путем вызова p.get_return_-
Объект (). Вызов get_return_object секвенируется перед вызовом initial_suspend и
вызывается не более одного раза.

VS2015 явно реализует старую версию этой статьи.

2

Другие решения

Других решений пока нет …