我正在使用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
调用的错误?
这是“修复”他们的榜样的正确方法吗?或者不是?
答案 0 :(得分:2)
我认为问题在于你需要第二个lambda的返回类型,它将被送到第三个(参见第一个任务的返回类型匹配FeedData
和第二个任务的参数类型) 。由于第二个任务没有返回任何void
似乎是正确的选择。如果您想使用第三个来捕获错误,则需要使用concurrency::task<void>
(基于引用)。
此外,根据引用,如果先行者(在本例中为第二个)任务失败,将调用此最终任务,并将报告在调用t.get()
时执行期间发生的任何错误。我不确定第一次失败时的情况,但你可以尝试通过从第一个任务中抛出一个arbirtary异常而发生的事情。