Search code examples
c++c++11templatesreferenceforwarding-reference

Need I really use another template in this case


template<class Key, class Value>
class ThreadSafeMap
{
    std::mutex m_;
    std::map<Key, Value> c_;

public:
    Value get(Key const& k) {
        std::unique_lock<decltype(m_)> lock(m_);
        return c_[k]; // Return a copy.
    }

    template<class Value2>
    void set(Key const& k, Value2&& v) {
        std::unique_lock<decltype(m_)> lock(m_);
        c_[k] = std::forward<Value2>(v);
    }
};

Thread safe std::map: Locking the entire map and individual values

I just read the link above and found the piece of code. It looks great with it to make a thread-safe map. I understand that in the function set, we used the reference collapsing rules on the second parameter v. But I don't understand why we need import another template<class Value2>, why can't we simply use the existing template class Value?


Solution

  • v is supposed to be declared as forwarding reference, which only works with templates. Then we need make set itself template.

    (emphasis mine)

    Forwarding references are a special kind of references that preserve the value category of a function argument, making it possible to forward it by means of std::forward. Forwarding references are either:

    1. function parameter of a function template declared as rvalue reference to cv-unqualified type template parameter of that same function template:

    If we declare set as a non-template as:

    template<class Key, class Value>
    class ThreadSafeMap
    {
        ...
    
        // non-template member function
        void set(Key const& k, Value&& v) {
            std::unique_lock<decltype(m_)> lock(m_);
            c_[k] = std::forward<Value2>(v);
        }
    };
    

    v will be just an rvalue-reference.