init-capture для ссылки на rvalue в Visual Studio 2013

Я хочу использовать System.Threading.Tasks.Task.ContinueWith .net в 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?

(Я хочу использовать лямбда, поэтому, пожалуйста, не говорите мне «используйте только структуру объекта-функции!»)

(Я попытался переместить захват в лямбда-выражении, но это не сработало..)

(Буду признателен, если вы не только ответите на мой вопрос, но и улучшите мой код)


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 Конечно, я пробовал .. но, черт возьми, VC++ 2013 не смог его скомпилировать!   -  person ikh    schedule 16.02.2014
comment
@ikh Я не уверен, где тебе нужно shared_ptr. -- Кроме того, в своем вопросе вы сказали, что пробовали решение из захвата Move в лямбда, но оно не сработало. Что именно не сработало?   -  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)
    );

Переход к обертке копирования я могу просто указать вам на stdfor-each">Как получить std::unique_ptr путем перемещения лямбды в std::for_each

person Lambage    schedule 31.12.2014