Подтвердить что ты не робот

С++ 11 продолжения async или попытка семантики .then()

Нижеприведенный код основан на Herb Sutter о реализации продолжения типа .then().

  template<typename Fut, typename Work>
auto then(Fut f, Work w)->std::future<decltype(w(f.get()))>
  { return std::async([=] { w(f.get()); }); }

Это будет использоваться как auto next = then(f, [](int r) { go_and_use(r); }); или подобное.

Это аккуратная идея, но, поскольку она стоит, не будет работать (фьючерсы перемещаются только и не копируются). Мне нравится идея, поскольку она может появиться в следующих версиях С++, насколько я могу предположить (хотя как .then() или даже ждать.)

Прежде чем делать фьючерсы разделяемыми или похожими, интересно, что сообщество подумает об этой реализации конкретно с улучшениями и предложениями (даже совместными фьючерсами)?

Заранее благодарим за любые предложения.

(Я знаю, что это исправление до тех пор, пока существует механизм, основанный на стандартах, поскольку он будет стоить нить (возможно))).

4b9b3361

Ответ 1

Я нахожу 3 проблемы с вышеуказанной реализацией:

  • Он будет работать, только если вы пройдете std::shared_future как Fut.
  • Продолжение может потребовать обработки исключений.
  • Он не всегда будет вести себя так, как ожидалось, так как если вы не укажете std::launch::async, он может быть отложен, поэтому продолжение не вызывается, как можно было бы ожидать.

Я попытался решить эти проблемы:

template<typename F, typename W, typename R>
struct helper
{
    F f;
    W w;

    helper(F f, W w)
        : f(std::move(f))
        , w(std::move(w))
    {
    }

    helper(const helper& other)
        : f(other.f)
        , w(other.w)
    {
    }

    helper(helper&& other)
        : f(std::move(other.f))
        , w(std::move(other.w))
    {
    }

    helper& operator=(helper other)
    {
        f = std::move(other.f);
        w = std::move(other.w);
        return *this;
    }

    R operator()()
    {
        f.wait();
        return w(std::move(f)); 
    }
};

}

template<typename F, typename W>
auto then(F f, W w) -> std::future<decltype(w(F))>
{ 
    return std::async(std::launch::async, detail::helper<F, W, decltype(w(f))>(std::move(f), std::move(w))); 
}

Используется следующим образом:

std::future<int> f = foo();

auto f2 = then(std::move(f), [](std::future<int> f)
{
    return f.get() * 2; 
});

Ответ 2

Вот решение, протестированное с g++ 4.8 и clang++ 3.2:

template<typename F, typename W>
auto then(F&& f, W w) -> std::future<decltype(w(f.get()))>
{
  cout<<"In thread id = "<<std::this_thread::get_id()<<endl;
  return std::async(std::launch::async, w, f.get());
}

void test_then()
{
  std::future<int> result=std::async([]{ return 12;});
  auto f = then(std::move(result), [](int r) {
    cout<<"[after] thread id = "<<std::this_thread::get_id()<<endl;
    cout<<"r = "<<r<<endl;
    return r*r;
  });
  cout<<"Final result f = "<<f.get()<<endl;
}