1

私はstd::async最初から実装しようとしていますが、移動のみのタイプの引数で問題が発生しました。その要点は、C++ 14 init-captures を使用すると、「移動によって」または「完全な転送によって」単一の変数をキャプチャできるようになりますが、「移動によって」または「完全な転送によって」パラメータパックをキャプチャすることはできないようです。 "、 init-capture ではパラメーター パックをキャプチャできないため、名前付きキャプチャでのみ使用できます。

回避策のように見えるものを見つけました。使用std::bindしてパラメーターパックを「移動して」キャプチャし、ラッパーを使用してパラメーターをバインドオブジェクトのストレージから実際に呼び出したい関数のパラメータースロットに移動します. あまり気にしなければエレガントに見えます。しかし、もっと良い方法があるに違いないと考えずにはいられません — 理想的には、まったく依存しない方法std::bindです。

std::bind(最悪の場合、それを回避するために自分でどれだけ再実装する必要があるかを知りたいです。この演習のポイントの一部は、物事がどのように実装され、一番下なので、依存関係が非常に複雑になるのはstd::bind本当に最悪です。)

私の質問は次のとおりです。

  • を使用せずにコードを機能させるにはどうすればよいstd::bindですか? (つまり、コア言語機能のみを使用します。一般的なラムダは公正なゲームです。)

  • 私のstd::bind回避策は防弾ですか?つまり、STL がstd::async機能し、私Asyncが失敗する例を誰かが示すことができますか?

  • C++1z でのパラメータ パック キャプチャをサポートするための議論や提案へのポインタは、ありがたく受け入れられます。

これが私のコードです:

template<typename UniqueFunctionVoidVoid>
auto FireAndForget(UniqueFunctionVoidVoid&& uf)
{
    std::thread(std::forward<UniqueFunctionVoidVoid>(uf)).detach();
}

template<typename Func, typename... Args>
auto Async(Func func, Args... args)
     -> std::future<decltype(func(std::move(args)...))>
{
    using R = decltype(func(std::move(args)...));
    std::packaged_task<R(Args...)> task(std::move(func));
    std::future<R> result = task.get_future();

#ifdef FAIL
    // sadly this syntax is not supported
    auto bound = [task = std::move(task), args = std::move(args)...]() { task(std::move(args)...) };
#else
    // this appears to work
    auto wrapper = [](std::packaged_task<R(Args...)>& task, Args&... args) { task(std::move(args)...); };
    auto bound = std::bind(wrapper, std::move(task), std::move(args)...);
#endif

    FireAndForget(std::move(bound));

    return result;
}

int main()
{
    auto f3 = [x = std::unique_ptr<int>{}](std::unique_ptr<int> y) -> bool { sleep(2); return x == y; };
    std::future<bool> r3 = Async(std::move(f3), std::unique_ptr<int>{});
    std::future<bool> r4 = Async(std::move(f3), std::unique_ptr<int>(new int));
    assert(r3.get() == true);
    assert(r4.get() == false);
}
4

1 に答える 1

2

argsオフラインで、パックを にキャプチャし、そのタプルを次のようなものを使用std::tupleして引数リストに再展開するという別のアプローチが提案されました(近くの C++17 標準ライブラリに間もなく登場します!)。taskstd::experimental::apply

    auto bound = [task = std::move(task), args = std::make_tuple(std::move(args)...)]() {
        std::experimental::apply(task, args);
    };

これははるかにきれいです。bind関連するライブラリ コードの量を「単なる」に減らしましたtuple。しかし、それはまだ私が取り除けるようにしたい大きな依存関係です!

于 2015-07-24T00:45:51.013 に答える