init-capture за препратка към rvalue във Visual Studio 2013

Искам да използвам .net System.Threading.Tasks.Task.ContinueWith в C++, така че пиша следната функция..

#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();
}

Този код работи на gcc 4.8.2 с -std=c++1y. (Не знам защо, но работи и с -std=c++11)

Но не работи на VC++ 2013. Предполагам, че е защото init-capture, функция на C++14. Как мога да стартирам този код с VC++ 2013?

(Искам да използвам ламбда, така че, моля, не ми казвайте „използвайте само структура функция-обект!“)

(Опитах Преместване на заснемане в lambda, но не работи..)

(Ще съм благодарен, ако не само отговорите на въпроса ми, но и подобрите кода ми)


person ikh    schedule 15.02.2014    source източник
comment
използвайте само структура функция-обект!   -  person Casey    schedule 15.02.2014
comment
@Casey добре, използвай просто функция-обект структура! не върви добре; Ако тогава, изглежда, че std::shared_ptr<std::future> е задължително и мисля, че не ме удовлетворява..   -  person ikh    schedule 15.02.2014
comment
@ikh Какво не е наред с функционален обект? Пример на живо Ако наистина искате да използвате ламбда, ще трябва да използвате някои обвивка, която прави нещо подобно на auto_ptr (а именно преместване вместо копиране).   -  person dyp    schedule 15.02.2014
comment
@dyp Разбира се, опитах го.. но suck VC++ 2013 не можа да го компилира!   -  person ikh    schedule 16.02.2014
comment
@ikh Не съм сигурен къде ще ти трябва shared_ptr. -- също така казахте във въпроса си, че сте опитали решението от Move capture в lambda, но не работи. Какво точно не проработи?   -  person dyp    schedule 16.02.2014
comment
@dyp О, отговорих отново. Неправилно видях източника ти..   -  person ikh    schedule 16.02.2014
comment
@dyp Изглежда, че функторът за копиране на VC++ вътре в библиотеката..   -  person ikh    schedule 16.02.2014
comment
Тази, предадена на std::async?   -  person dyp    schedule 16.02.2014


Отговори (2)


За съжаление тази функция все още не присъстваше във Visual Studio 2013. Беше пусната през юни 2014 г. с Visual Studio "14" CTP (технически преглед на общността, който е с алфа качество и не е готов за производствен код). Да цитираш:

Ето подобренията за Visual C++:

Обобщено улавяне на ламбда: Можете да присвоите резултата от оценяването на израз на променлива в клаузата за улавяне на ламбда. Това позволява екземпляр от тип само за преместване да бъде уловен по стойност.

Както беше посочено в коментарите: като заобиколно решение за Visual Studio 2013, можете да направите свой собствен функционален обект с локални променливи, инициализирани чрез конструктора. Да, това е гадно, но това е стандартният трик, преди да бъдат изобретени ламбдите. Такъв беше и случаят с полиморфните ламбда, докато не бяха поддържани (заобиколно решение: функционален обект с шаблонен operator()) и в момента с текущо забранените constexpr ламбда (заобиколно решение: constexpr функционален обект от литерален тип).

person TemplateRex    schedule 22.07.2014

Съществуват 2 други опции, използващи std::bind и писане на ход върху обвивката на копие.

така че можете да направите

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

Преместването на обвивката за копиране Мога просто да ви насоча към Как да заснема std::unique_ptr чрез преместване за ламбда в std::for_each

person Lambage    schedule 31.12.2014