1

I want use .net's System.Threading.Tasks.Task.ContinueWith in C++, so I write the following function..

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

This code works on gcc 4.8.2 with -std=c++1y. (I don't know why, but it works with -std=c++11, too)

But it doesn't work on VC++ 2013. I guess it's because init-capture, a C++14 feature. How can I run this code with VC++ 2013?

(I want to use lambda, so please don't tell me "use just function-object struct!")

(I tried Move capture in lambda, but it doesn't work..)

(I'll appreciate if you not only answer my question but also imporve my code)

Community
  • 1
  • 1
ikh
  • 10,119
  • 1
  • 31
  • 70
  • 1
    use just function-object struct! – Casey Feb 15 '14 at 07:28
  • @Casey well, "use just function-object struct!" doesn't go well; If then, it seems that `std::shared_ptr` is required and I think it doesn't satisfy me.. – ikh Feb 15 '14 at 07:35
  • @ikh What's wrong with a function object? [Live example](http://coliru.stacked-crooked.com/a/cf443083851f0717) If you really want to use a lambda, you'll have to use some wrapper that does something similar to `auto_ptr` (namely, move instead of copy). – dyp Feb 15 '14 at 13:07
  • @dyp Of course, I tried it.. but suck VC++ 2013 could not compile it! – ikh Feb 16 '14 at 00:43
  • @ikh I'm not sure where you'd need `shared_ptr`. -- also, you said in your question you tried the solution from "Move capture in lambda" but it didn't work. What exactly didn't work? – dyp Feb 16 '14 at 00:45
  • @dyp Oh, I re-replied. I saw your source incorrectly.. – ikh Feb 16 '14 at 00:47
  • @dyp It seems that VC++ "copy" functor inside library.. – ikh Feb 16 '14 at 00:51
  • The one passed to `std::async`? – dyp Feb 16 '14 at 00:55

2 Answers2

1

Unfortunately, this feature was not present yet in Visual Studio 2013. It was released in June 2014 with the Visual Studio "14" CTP (community tech preview, which is alpha-quality and not ready for production code). To quote:

Here are the improvements for Visual C++:

Generalized lambda capture: You can assign the result of evaluating an expression to a variable in the capture clause of a lambda. This allows an instance of a move-only type to be captured by value.

As was pointed out in the comments: as a work-around for Visual Studio 2013, you can make your own function object with local variables initialized through the constructor. Yes, this sucks, but it has been the standard trick before lambdas were invented. It was also the case with polymorphic lambdas until they were supported (workaround: function object with templated operator()) and currently with the currently disallowed constexpr lambdas (workaround: constexpr function object of literal type).

sstn
  • 3,050
  • 19
  • 32
TemplateRex
  • 69,038
  • 19
  • 164
  • 304
0

2 other options exist, using std::bind and writing a move on copy wrapper.

so you could do

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

The move on copy wrapper I can just point you to How to capture std::unique_ptr "by move" for a lambda in std::for_each

Community
  • 1
  • 1
Lambage
  • 367
  • 3
  • 8