2012-06-07 53 views
3

我正在通過msdn(link)上的「教程:使用C++創建您的第一個Metro風格應用程序」。很快進入它的「第二部分」,我遇到了一個錯誤。我正在使用Visual Studio 2012 Release Candidate(最新版本)在Windows 8 VM Release Preview(5月31日)上運行此操作。C++ Metro應用程序教程 - 任務延續編譯錯誤

在添加3個新的metro頁面,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 

我拿出lambda表達式一次一個(和放在分號所以它會編譯),如果我有前兩個,這很好,但鏈中的最後一個導致錯誤。但如果我只是最後一個,它編譯。或者如果我用它編譯的第一個和第三個來完成它。或者只有前兩個。

問題是第二個lambda?頭文件庫對void返回類型感到困惑嗎?或者是別的什麼?根據這個理論,我將「最終」處理程序聲明修改爲:

 // 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),這是正確的嗎?有該網頁上稱爲節「基於價值的對戰基於任務的延續」,也就是複製如下:

給定一個任務對象,其返回類型爲T,則可以提供 T型或任務的價值它的繼續任務。類型T需要 的延續被稱爲基於價值的延續。當先行任務 完成且沒有錯誤且未取消時,將計劃執行基於值的 延續。以 類型任務作爲其參數的延續稱爲基於任務的延續。 A 基於任務的延續總是安排在 先行任務完成時執行,即使先前任務被取消或 引發異常。然後你可以調用task :: get來獲得 的前面任務的結果。如果先行任務被取消,task :: get throws concurrency :: task_canceled。如果先行任務拋出異常,則task :: get將拋出異常。當其先行任務 取消時,基於任務的 延續未標記爲已取消。

這是說,對錯誤處理的最終延續應該是最終.then延續的類型,還是原來的create_task的類型?如果這是最後的(正如我上面用void所做的那樣),這個延續是否會實際處理所有以上的錯誤,或者只是最後的.then調用的錯誤?

這是「解決」他們的例子的正確方法嗎?或不?

+0

我要求刪除這個問題,事實證明這是由於本教程無法跟上測試版的編譯器。這種差距不再存在,目前的教程工作100%。 –

回答

2

我認爲問題在於你需要從第二個lambda返回的類型將被饋送到第三個(請參閱匹配的FeedData第一個任務的返回類型和第二個參數類型)。由於第二項任務不會返回任何東西void似乎是正確的選擇。由於您想使用第三個來捕獲錯誤,因此您需要使用concurrency::task<void>(根據報價)。

此外,根據報價,如果先前(本例中的第二個)任務失敗並且將在調用t.get()時報告執行期間發生的任何錯誤,則會調用此最終任務。我不確定第一次失敗時的情況,但是您可以嘗試通過從第一項任務中拋出一個異常例外情況。

+0

今天我有些空閒時,我肯定會試試看看會發生什麼。可能只是使用不存在的Feed URL或可能發生的事情,以便獲得一系列「良好」結果,而且一個保證不良結果。 –