【问题标题】:Compilation error with C++ Metro App Tutorial - task continuationC++ Metro App Tutorial 的编译错误 - 任务继续
【发布时间】:2012-06-11 15:39:19
【问题描述】:

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

在添加 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(并放入分号以便编译),如果我有前两个,那很好,但链中的最后一个会导致错误。但是如果我 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 或 task 到其后续任务。延续 类型 T 被称为基于值的延续。基于价值的 continuation 计划在前面的任务时执行 没有错误地完成并且没有被取消。延续 类型任务作为其参数被称为基于任务的延续。一种 基于任务的延续总是安排在当 前面的任务完成,即使前面的任务被取消或 抛出异常。然后你可以调用 task::get 来获取结果 先前的任务。如果前面的任务被取消,task::get 抛出并发::task_canceled。如果前面的任务抛出了一个 异常,task::get 重新抛出该异常。基于任务的 当其先前的任务是继续时,它不会被标记为已取消 取消。

这是说错误处理的最终延续应该是最终.then延续的类型,还是原始create_task的类型?如果它是最终的(就像我在上面对void 所做的那样),这个延续实际上会处理所有上述错误,还是只处理最终的.then 调用的错误?

这是“修复”他们的例子的正确方法吗?还是不行?

【问题讨论】:

  • 我要求删除这个问题,因为事实证明这是由于教程没有跟上编译器的 beta 版本造成的。这种差异不再存在,当前教程 100% 有效。

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


【解决方案1】:

我认为问题在于您需要来自第二个 lambda 的返回类型,该类型将被馈送到第三个(有关第一个任务的返回类型和第二个任务的参数类型,请参见匹配的 FeedData)。由于第二个任务没有返回任何东西void 似乎是正确的选择。由于您想使用第三个来捕获错误,因此您需要使用concurrency::task&lt;void&gt;(基于报价)。

此外,根据引用,如果前面的(本例中的第二个)任务失败,则将调用最终任务,并在调用 t.get() 时报告其执行过程中发生的任何错误。我不确定第一个任务失败的情况,但是您可以通过从第一个任务中抛出任意异常来尝试会发生什么。

【讨论】:

  • 今天有空的时候,我肯定会尝试一下,看看会发生什么。可能只是有一个不存在的提要 URL 或实际可能发生的事情,所以我得到了一系列“好”的结果,一个肯定是坏的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-10
  • 2014-02-04
  • 1970-01-01
  • 2020-09-23
相关资源
最近更新 更多