使用C ++ Metro App Tutorial进行编译错误 - 任务继续

时间:2012-06-07 14:52:36

标签: c++ windows-8 microsoft-metro visual-studio-2012 ppl

我正在使用msdn(link)上的“教程:使用C ++创建您的第一个Metro风格应用程序”。很快进入“第2部分”,我遇到了一个错误。我正在使用Visual Studio 2012 Release Candidate(最新版本)在Windows 8 VM Release Preview(5月31日)上运行它。

在添加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

我一次取出一个lambdas(然后放入分号以便编译),如果我有前两个,那很好,但是链中的最后一个会导致错误。但如果我create_task只是最后一个,它就会编译。或者,如果我使用第一个和第三个进行编译。或者只有前两个。

问题是第二个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被称为基于值的延续。以价值为基础   继续计划在先前任务执行时执行   完成没有错误,不会被取消。需要的延续   type task作为其参数称为基于任务的延续。一个   基于任务的延续始终安排在执行时执行   先前的任务完成,即使先前的任务被取消或   抛出一个例外。然后,您可以调用task :: get来获取结果   先前的任务。如果先前任务被取消,则task :: get   抛出并发:: task_canceled。如果先前的任务扔了一个   异常,task :: get重新抛出异常。以任务为基础   延续在其先前任务未被标记为已取消   取消。

这是说错误处理的最后一个延续应该是最终.then延续的类型,还是原始create_task的类型?如果它是最后一个(正如我上面用void所做的那样),这个延续会不会真正处理上述所有错误,或者只是最终.then调用的错误?

这是“修复”他们的榜样的正确方法吗?或者不是?

1 个答案:

答案 0 :(得分:2)

我认为问题在于你需要第二个lambda的返回类型,它将被送到第三个(参见第一个任务的返回类型匹配FeedData和第二个任务的参数类型) 。由于第二个任务没有返回任何void似乎是正确的选择。如果您想使用第三个来捕获错误,则需要使用concurrency::task<void>(基于引用)。

此外,根据引用,如果先行者(在本例中为第二个)任务失败,将调用此最终任务,并将报告在调用t.get()时执行期间发生的任何错误。我不确定第一次失败时的情况,但你可以尝试通过从第一个任务中抛出一个arbirtary异常而发生的事情。