私は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);
}