The implementation seems right to me and does the job.
However, providing different implementations for lvalues ββand rvalues ββmight be a good idea in your case. The main reason I can think of is that the output of template type arguments does not work for braced-init lists. Consider:
struct foo { foo(std::initializer_list<int>) { } };
With OP code (*)
b.push(f); // OK b.push({1, 2, 3}); // Error
If the following BlockingQueue::push overloads are provided instead:
void push(const T& value) { container_.push(value); } void push(T&& value) { container_.push(std::move(value)); }
Then the line that was used for the failure will work fine.
The same arguments apply to aggregates. For example, if foo was defined as
struct foo { int a, b, c; };
the same behavior would be observed as described above.
My conclusion is that if you want BlockingQueue support more types (including aggregates or types with constructors that accept std::initializer_list s), then it is better to provide two different overloads.
(*) A small correction in the OP code: in static_assert you need to use typename
typename std::remove_reference<U>::type>::value ^^^^^^^^
source share