0
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?

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
Yves
  • 11,597
  • 17
  • 83
  • 180

1 Answers1

2

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.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • I think their asking why not use the outer template, on the class, i.e. use `value` template value. That also seems to be "working with templates". – kabanus Aug 05 '21 at 04:36
  • Thanks, but not for me at least - you could write *`v2` will be an rvalue-reference* and it will not be clear which is right. In essence, I think you need to make the distinction of what happens in both cases (which are valid in the sense they are allowed by the language), perhaps with a differentiating usage example. – kabanus Aug 05 '21 at 04:42
  • TBH I thought allowing `Value2` was just for more flexibility in auto-casting rules and the like, not rvalue-lvalue stuff. – kabanus Aug 05 '21 at 04:42
  • I guess this could be a "What is a forwarding reference" question, since your answer will only be clear to language (semi) experts., I think – kabanus Aug 05 '21 at 04:44
  • Anyway, upvoted for being the best kind of correct, but I'm not sure this is enough for OP. – kabanus Aug 05 '21 at 04:45
  • @kabanus Hmm, I'm not sure what OP's confusing, is it why forwarding reference should be used, or OP knows it should be forwarding reference but why need import another `template`. Anyway I tried to add both aspects. – songyuanyao Aug 05 '21 at 04:49