在Visual Studio 2013中初始捕获rvalue引用

时间:2014-02-15 07:04:02

标签: c++ c++11 lambda rvalue-reference c++14

我想在C ++中使用.net的System.Threading.Tasks.Task.ContinueWith,所以我写了以下函数..

#include <iostream>
#include <functional>
#include <future>

template <typename Func, typename Ret>
auto continue_with(std::future<Ret> &&fu, Func func)
    -> std::future<decltype(func(fu.get()))>
{
    return std::async(
        [fu = std::move(fu), func]() mutable { return func(fu.get()); }
        );
}

template <typename Func>
auto continue_with(std::future<void> &&fu, Func func)
    -> std::future<decltype(func())>
{
    return std::async(
        [fu = std::move(fu), func]() mutable { fu.get(); return func(); }
        );
}

int main()
{
    std::future<void> fu = std::async([]{ std::cout << "fu" << std::endl; });
    std::future<void> fu2 = continue_with(
        std::move(fu),
        []{ std::cout << "fu2" << std::endl; }
        );
    fu2.get();
    std::cout << "fu continue complete" << std::endl;

    std::future<int> retfu = std::async([]{ std::cout << "retfu" << std::endl; return 3; });
    std::future<int> retfu2 = continue_with(
        std::move(retfu),
        [](int result){ std::cout << "retfu2 " << result << std::endl; return result + 1; }
        );
    int ret = retfu2.get();
    std::cout << "retfu continue complete : " << ret << std::endl; 

    std::cin.get();
}

此代码适用于带有-std=c++1y的gcc 4.8.2。 (我不知道为什么,但它也适用于-std=c++11

但它在VC ++ 2013上不起作用。我想这是因为init-capture,一个C ++ 14特性。如何使用VC ++ 2013运行此代码?

(我想使用lambda,所以请不要告诉我“只使用函数对象结构!”)

(我试过Move capture in lambda,但它不起作用..)

(如果您不仅回答我的问题而且还要改进我的代码,我将不胜感激)

2 个答案:

答案 0 :(得分:1)

不幸的是,此功能在Visual Studio 2013中尚未出现。它于2014年6月发布,带有Visual Studio "14" CTP(社区技术预览,这是alpha质量,尚未准备好生产代码)。引用:

  

以下是Visual C ++的改进:

     

广义lambda捕获:您可以指定评估结果   表达式到lambda的capture子句中的变量。这个   允许按值捕获仅移动类型的实例

正如评论中指出的:作为Visual Studio 2013的解决方法,您可以使用通过构造函数初始化的局部变量创建自己的函数对象。是的,这很糟糕,但它是发明lambdas之前的标准技巧。在支持多态lambda之前(解决方法:带有模板化operator()的函数对象)并且当前使用当前不允许的constexpr lambdas(解决方法:constexpr文字类型的函数对象也是如此)。

答案 1 :(得分:0)

存在2个其他选项,使用std :: bind并在复制包装上写一个移动。

所以你可以做到

return std::async(std::bind(
    [func](std::future<void> & fu) mutable { fu.get(); return func(); },
    std::move(fu)
    );

复制包装上的移动我可以指向How to capture std::unique_ptr "by move" for a lambda in std::for_each