문제

In elaboration of my previous question and question, I'd like to understand what goes on in this real scenario. I have the following template function:

template <typename Key, typename Value, typename HashFunction, typename Equals>
void FastHash<Key, Value, HashFunction, Equals>::Insert(const Key& key, const Value& value)
{
    Insert(std::make_pair(key, value));
}

called with, for instance, a mixture of lvalues and rvalues, like in this call:

std::string name = "The Great";
hashTable.Insert(name, "Gatsby");

(for testing purposes). Insert above calls

template <typename Key, typename Value, typename HashFunction, typename Equals>
void FastHash<Key, Value, HashFunction, Equals>::Insert(pair<const Key, Value>&& keyValuePair)
{
    if (buckets.size() == 0)
    {
        buckets.resize(1);
    }

    HashFunction hash;
    unsigned long hashValue = hash(keyValuePair.first) % buckets.size();
    buckets[hashValue].push_back(std::move(keyValuePair));
}

A few questions:

1. I would expect making a pair one of whose elements is a literal string to be undefined behaviour, owing to passing by reference. Is that so?

2. When I step into the make_pair line, the code first calls make_pair(_Ty1&& _Val1, _Ty2&& _Val2), so it seems that the compiler is interpreting key and value as rvalues. Why?

3. The next call before going into the second Insert method is pair(pair<_Other1, _Other2>&& _Right). This happens irrespective of whether the second Insert takes an && or a const &. What's going on here?

4. Tied to this last, should the second Insert take a const pair& or a pair&&, given what it does?

Update: After watching Scott Meyer's excellent video on universal references, reading on template deduction and reference collapsing rules, and with your help I can answer 1, 2, and 4. But I still cannot understand why the pair's move constructor is called just before the Insert call. Any help on that?

도움이 되었습니까?

해결책

The next call before going into the second Insert method is pair(pair<_Other1, _Other2>&& _Right). This happens irrespective of whether the second Insert takes an && or a const &. What's going on here?

That is std::pair's converting constructor: it's converting the pair that you pass - std::make_pair(key, value) - from std::pair<Key, Value> to the second Insert functions's parameter type std::pair<const Key, Value>. You could avoid the conversion if you specify the pair type yourself instead of having std::make_pair deduce it:

Insert(std::pair<const Key, Value>{key, value});

Of course, this is copying the parameters into a pair, and in C++11 we have the rule of thumb that if you are going to copy something you should accept it by value. So maybe implement this Insert as:

template <typename Key, typename Value, typename HashFunction, typename Equals>
void FastHash<Key, Value, HashFunction, Equals>::Insert(Key key, Value value)
{
    Insert(std::pair<const Key, Value>{std::move(key), std::move(value)});
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top