When writing a thread-safe std::stack
wrapper I made the following two overloads for push
:
void push(const value_type& value)
{
auto guard = std::scoped_lock{_mutex};
_stack.push(value);
_cv.notify_one();
}
void push(value_type&& value)
{
auto guard = std::scoped_lock{_mutex};
_stack.push(std::move(value));
_cv.notify_one();
}
They are nearly the same except that one takes a const lvalue reference and one takes an rvalue reference. Normally I would use perfect forwarding to deal with this (now using the glorious C++20 abbreviated template declaration):
void push(auto&& value)
{
auto guard = std::scoped_lock{_mutex};
_stack.push(std::forward<decltype(value)>(value));
_cv.notify_one();
}
The problem here is that this accepts any type, while it should accept only value_type
and references to it.
Is there some standard way to solve this? So far I came up with two approaches. Either use a std::enable_if
to somehow check if the template type is value_type
or a reference to it, or use a concept.
You can assert it:
template<typename T>
void push(T&& value)
{
static_assert(is_same_v<remove_reference_t<T>, value_type>);
// ...
}
You could alternatively use is_convertible
instead of is_same
so it works more naturally.