Я работаю над «Учебным пособием: создайте свое первое приложение стиля Metro с помощью C++» в msdn (link). И вскоре в «часть 2» этого я столкнулся с ошибкой. Я запускаю это в предварительном выпуске Windows 8 VM Release (31 мая) с кандидатом на выпуск Visual Studio 2012 (последний).Ошибка компиляции с C++ Metro App Tutorial - продолжение задачи
Где я нахожусь в разделе кода после добавления трех новых страниц метро, ItemsPage, SplitPage и новой «DetailPage». Добавление тех прошло хорошо, но когда я добавить код непосредственно ниже, в разделе под названием «Чтобы изменить асинхронный код, который инициализирует модель данных» он создает две копии ниже ошибки:
error C2893: Failed to specialize function template ''unknown-type' Concurrency::details::_VoidReturnTypeHelper(_Function,int,...)' c:\program files (x86)\microsoft visual studio 11.0\vc\include\ppltasks.h 404 1 SimpleBlogReader
Тогда я вынул весь код из этого раздела и начал добавлять его за штуку за раз, чтобы узнать, где была ошибка «действительно», поскольку я, очевидно, не модифицировал этот стандартный заголовочный файл. Оказывается, это в цепи задач в методе App::InitDataSource
:
SyndicationClient^ client = ref new SyndicationClient();
for(wstring url : urls)
{
// Create the async operation.
// feedOp is an IAsyncOperationWithProgress<SyndicationFeed^, RetrievalProgress>^
auto feedUri = ref new Uri(ref new String(url.c_str()));
auto feedOp = client->RetrieveFeedAsync(feedUri);
// Create the task object and pass it the async operation.
// SyndicationFeed^ is the type of the return value
// that the feedOp operation will eventually produce.
// Then, initialize a FeedData object with the feed info. Each
// operation is independent and does not have to happen on the
// UI thread. Therefore, we specify use_arbitrary.
create_task(feedOp).then([this] (SyndicationFeed^ feed) -> FeedData^
{
return GetFeedData(feed);
}, concurrency::task_continuation_context::use_arbitrary())
// Append the initialized FeedData object to the list
// that is the data source for the items collection.
// This has to happen on the UI thread. By default, a .then
// continuation runs in the same apartment thread that it was called on.
// Because the actions will be synchronized for us, we can append
// safely to the Vector without taking an explicit lock.
.then([fds] (FeedData^ fd)
{
fds->Append(fd);
// Write to VS output window in debug mode only. Requires <windows.h>.
OutputDebugString(fd->Title->Data());
OutputDebugString(L"\r\n");
})
// The last continuation serves as an error handler. The
// call to get() will surface any exceptions that were raised
// at any point in the task chain.
.then([this] (concurrency::task<SyndicationFeed^> t)
{
try
{
t.get();
}
// SyndicationClient throws E_INVALIDARG
// if a URL contains illegal characters.
catch(Platform::InvalidArgumentException^ e)
{
// TODO handle error. For example purposes
// we just output error to console.
OutputDebugString(e->Message->Data());
}
}); //end task chain
Я вынул лямбды один на один раз (и поставить в точку с запятой, так что бы скомпилировать), и если у меня есть первые два, это нормально, но последний в цепочке вызывает ошибку. Но если я create_task
только последний, он компилируется. Или, если я делаю это с первого и третьего, он компилируется. Или только с первыми двумя.
Является ли проблема второй лямбдой? Является ли библиотека заголовков путаной по типу возвращаемого типа? Или что-то еще? Работая над этой теорией, я модифицировал декларацию «окончательного» обработчика следующим образом:
// The last continuation serves as an error handler. The
// call to get() will surface any exceptions that were raised
// at any point in the task chain.
.then([this] (concurrency::task<void> t)
Теперь ЭТО компилируется. Но согласно документу в msdn (here), это правильно? Там в раздел под названием «Value-Based Versus основе задач продолжений» на этой странице, скопированный ниже:
Учитывая объект задача, возвращаемый тип T, вы можете указать значение типа T или задачей его продолжения. Продолжение, которое принимает тип T, называется продолжением на основе значений. Продолжение на основе значений планируется выполнить, когда антецедентная задача завершается без ошибок и не отменяется. Продолжение, которое принимает задание типа как его параметр, называется продолжением на основе задач. A продолжение на основе задач всегда запланировано для выполнения, когда завершающая задача заканчивается, даже если антецедентная задача отменена или выдает исключение. Затем вы можете вызвать задачу :: get, чтобы получить результат антецедент. Если антецедентная задача была отменена, задание :: get throws concurrency :: task_canceled. Если предшествующая задача выбрала исключение , задача :: get rethrows это исключение. Продолжение на основе задачи продолжение не отмечено как отменено, когда антецедентная задача отменена.
Является ли это о том, что окончательное продолжение для обработки ошибок должно быть типом конечного .then
продолжения, или типа оригинала create_task
? Если это окончательный вариант (как я уже говорил выше с void
), продолжит ли это продолжение все вышеперечисленные ошибки или только ошибки для окончательного вызова .then
?
Это правильный способ «исправить» их пример? Или нет?
Я прошу удалить этот вопрос, так как выясняется, что это было вызвано тем, что учебник не соответствовал бета-версии компилятора. Это несоответствие больше не существует, и текущий учебник работает на 100%. –