template class threadsafe_queue { private: node* get_tail() { std::lock_guard tail_lock(tail_mutex); return tail; } std::unique_ptr pop_head() { std::unique_ptr const old_head = std::move(head); head = std::move(old_head->next); return old_head; } std::unique_lock wait_for_data() { std::unique_lock head_lock(head_mutex); data_cond.wait(head_lock, [&] { return head != get_tail(); }); return std::move(head_lock); } std::unique_ptr wait_pop_head() { std::unique_lock head_lock(wait_for_data()); return pop_head(); } std::unique_ptr wait_pop_head(T& value) { std::unique_lock head_lock(wait_for_data()); value = std::move(*head->data); return pop_head(); } public: std::shared_ptr wait_and_pop() { std::unique_ptr const old_head = wait_pop_head(); return old_head->data; } void wait_and_pop(T& value) { std::unique_ptr const old_head = wait_pop_head(value); } };