c++perfect-forwardingfunction-templatesforwarding-reference

How do you take a forwarding reference to a specific type?


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.


Solution

  • 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.