简体   繁体   中英

Why is try_emplace not implemented for std::multimap?

C++17 introduces the try_emplace method for std::map , so now I can write code like below:

struct Test
{
    Test(int i, int j){}
};
std::map<int, Test> tmap;
tmap.try_emplace(10, 10, 10);

But there is no try_emplace for std::multimap<int, Test> , so piecewise_construct is still needed.

Is there a technical reason for this?

is there a technical reason for this?

Yes. The purpose of try_emplace() is to not do anything if the key already exists in the map. But for std::{unordered_,}multi{map,set} , you can have multiple values for each key. That is, indeed, the point of these containers: to have multiple values for a given key.

As a result, try_emplace() cannot fail for these containers - so it would be confusing and pointless to provide such a function.


Based on the comments, it seems that the motivation is just the part of try_emplace() that makes it easier to emplace a value. You can write a helper function for that:

template <typename Map, typename Key, typename... Args>
auto emplace_value(Map& map, Key&& key, Args&&... args) {
    return map.emplace(std::piecewise_construct,
                       std::forward_as_tuple(std::forward<Key>(key)),
                       std::forward_as_tuple(std::forward<Args>(args)...));
}

Which would let you write emplace_value(tmap, 10, 10, 10) , even for {unordered_,}multimap .

It is not necessary since for multimap case since there is no unique key, try_emplace would never fail. The rational for adding try_emplace to map was all the error prone code needed to deal with the case that key already exists, see the proposal n4279 ( emphasis mine ):

The existing interface of unique-keyed map containers (std::map, std::unordered_map) is slightly underspecified, which makes certain container mutations more complicated to write and error-prone than necessary . This paper describes new member function templates to fill this gap.

The justification and rationale for the new interface are given in N3873. The initial reaction to N3873 in Issaquah was that the existing map interfaces should be fixed rather than adding new interfaces. We explored this idea in N4006 in Rapperswil and decided that the original proposal was preferable (with some name changes). This paper only summarises the proposed extension without repeating the original discussion. We only restate the motivating code snippet here for motivation:

 std::map<std::string, std::unique_ptr<Foo>> m; m["foo"] = nullptr; auto ptr = std::make_unique_ptr<Foo>; auto res = m.emplace("foo", std::move(ptr)); assert(ptr); // ??? (may or may not fire) 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM