2012-06-07 2 views
3

Я работаю над «Учебным пособием: создайте свое первое приложение стиля 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?

Это правильный способ «исправить» их пример? Или нет?

+0

Я прошу удалить этот вопрос, так как выясняется, что это было вызвано тем, что учебник не соответствовал бета-версии компилятора. Это несоответствие больше не существует, и текущий учебник работает на 100%. –

ответ

2

Я думаю, проблема в том, что вам нужен тип возврата из второго лямбда, который будет подаваться на третий (см. Соответствие FeedData для типа возврата первой задачи и типа параметра для второго). Поскольку вторая задача ничего не возвращает void кажется правильным выбором. Поскольку вы хотите использовать третий для захвата ошибок, вам нужно будет пойти с concurrency::task<void> (на основе цитаты).

Кроме того, на основании цитаты эта заключительная задача будет вызвана, если антецедент (второй в этом случае) не выполнен и сообщит о любых ошибках, которые произошли во время его выполнения при вызове t.get(). Я не уверен в случае, когда первый сбой, но вы можете попробовать, что происходит, выбрасывая arbirtary исключение из первой задачи.

+0

Когда я получаю некоторое свободное время сегодня, я определенно собираюсь попробовать это и посмотреть, что произойдет. Вероятно, просто с несуществующим URL-адресом или чем-то, что действительно может произойти, так что я получаю серию «хороших» результатов и один гарантированный плохой. –