Skip to content

Instantly share code, notes, and snippets.

@geneotech
Last active September 15, 2017 20:42
Show Gist options
  • Save geneotech/c9e8177b34dbace6b1fa23129977c9d1 to your computer and use it in GitHub Desktop.
Save geneotech/c9e8177b34dbace6b1fa23129977c9d1 to your computer and use it in GitHub Desktop.
Thread templates
#pragma once
#include <future>
#include <optional>
template <class T>
bool is_ready(const std::future<T>& f) {
return f.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
}
template <class T>
class packaged_future {
std::optional<T> value;
std::future<void> future;
template <class F>
void init(F&& task) {
future = std::async(std::launch::async,
[this, task]() {
value.emplace(task());
}
);
}
public:
packaged_future() = default;
template <class F>
packaged_future(F&& task) {
init(std::forward<F>(task));
}
/*
We can't rely on the default assignment behaviour,
because if the right-hand side is a temporary,
constructor of the temporary will launch a task
to emplace into 'std::optional<T> value' belonging to that temporary,
which is soon to be destroyed.
*/
template <class F>
packaged_future& operator=(F&& task) {
init(std::forward<F>(task));
return *this;
}
void wait() const {
future.wait();
}
bool is_ready() const {
return future.valid() && ::is_ready(future);
}
auto& get() {
wait();
return *value;
}
const auto& get() const {
wait();
return *value;
}
};
template <class F>
auto make_packaged_future(F&& task) {
return packaged_future<std::invoke_result_t<F>>(std::forward<F>(task));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment