std::flat_map::try_emplace(3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

πŸ’… std::flat_map::try_emplace(3)

Bestie, welcome to the std::flat_map::try_emplace page from the C++ Standard Libary (manual section (3)). It’s all since C++23, and it’s giving β€œI will insert your key only if it’s not already there” energy. Periodt. ✨


🌸 NAME

std::flat_map::try_emplace β€” std::flat_map::try_emplace

It’s the try_emplace member of std::flat_map, bestie. The name is literally the name, no cap. 🫢

✨ Synopsis

template< class... Args >
std::pair<iterator, bool> try_emplace( const key_type& k,
(1) (since C++23)
Args&&... args );
template< class... Args >
std::pair<iterator, bool> try_emplace( key_type&& k, Args&&...
(2) (since C++23)
args );
template< class K, class... Args >
(3) (since C++23)
std::pair<iterator, bool> try_emplace( K&& k, Args&&... args );
template< class... Args >
iterator try_emplace( const_iterator hint, const key_type& k,
(4) (since C++23)
Args&&... args );
template< class... Args >
iterator try_emplace( const_iterator hint, key_type&& k, Args&&...
(5) (since C++23)
args );
template< class K, class... Args >
iterator try_emplace( const_iterator hint, K&& k, Args&&... args
(6) (since C++23)
);

So here’s the vibe check: if a key equivalent to k already exists in the container, it does nothing. Otherwise, it inserts a new element into the underlying containers c with key k and value constructed with args. πŸ’–

Overloads 1,2,4,5 are equivalent to:

auto key_it = ranges::upper_bound(c.keys, k, compare);
auto value_it = c.values.begin() + std::distance(c.keys.begin(),
       key_it);
c.keys.insert(key_it, std::forward<decltype(k)>(k));
c.values.emplace(value_it, std::forward<Args>(args)...);

Overloads 3,6 are equivalent to:

auto key_it = ranges::upper_bound(c.keys, k, compare);
auto value_it = c.values.begin() + std::distance(c.keys.begin(),
       key_it);
c.keys.emplace(key_it, std::forward<K>(k));
c.values.emplace(value_it, std::forward<Args>(args)...);

The conversion from k into key_type must construct an object u, for which find(k) == find(u) is true. Otherwise, the behavior is undefined. Undefined behavior, bestie β€” do not play with that. 😭

These overloads participate in overload resolution only if :

  • The qualified-id Compare::is_transparent is valid and denotes a type.
  • std::is_constructible_v<key_type, K> is true.
  • std::is_assignable_v<mapped_type&, Args...> is true.
  • For (3) only, std::is_convertible_v<K&&, const_iterator> and std::is_convertible_v<K&&, iterator> are both false.
Information on iterator invalidation is copied from here

πŸŽ€ Parameters

  • k β€” the key used both to look up and to insert if not found.
  • hint β€” iterator to the position before which the new element will be inserted.
  • args β€” arguments to forward to the constructor of the element.

πŸ’– Return value

  • 1-3) β€” same as for emplace.
  • 4-6) β€” same as for emplace_hint.

πŸŒ€ Complexity

  • 1-3) β€” same as for emplace.
  • 4-6) β€” same as for emplace_hint.

🧚 Notes

Unlike insert or emplace, these functions do not move from rvalue arguments if the insertion does not happen, which makes it easy to manipulate maps whose values are move-only types, such as std::flat_map<std::string, std::unique_ptr<foo>>. In addition, try_emplace treats the key and the arguments to the mapped_type separately, unlike emplace, which requires the arguments to construct a value_type (that is, a std::pair). ✨

Overloads (3,6) can be called without constructing an object of type key_type.

🌈 Example

// Run this code

#include <flat_map>
#include <iostream>
#include <string>
#include <utility>

void print_node(const auto& node)
{
    std::cout << '[' << node.first << "] = " << node.second << '\n';
}

void print_result(auto const& pair)
{
    std::cout << (pair.second ? "inserted: " : "ignored:  ");
    print_node(*pair.first);
}

int main()
{
    using namespace std::literals;
    std::map<std::string, std::string> m;

    print_result(m.try_emplace( "a", "a"s));
    print_result(m.try_emplace( "b", "abcd"));
    print_result(m.try_emplace( "c", 10, 'c'));
    print_result(m.try_emplace( "c", "Won't be inserted"));

    for (const auto& p : m)
        print_node(p);
}

Output:

inserted: [a] = a
inserted: [b] = abcd
inserted: [c] = cccccccccc
ignored:  [c] = cccccccccc
[a] = a
[b] = abcd
[c] = cccccccccc

πŸ¦‹ See also

  • emplace β€” constructs element in-place (public member function)
  • emplace_hint β€” constructs elements in-place using a hint (public member function)
  • insert β€” inserts elements (public member function)
  • insert_or_assign β€” inserts an element or assigns to the current element if the key already exists (public member function)

That’s the whole vibe, bestie. Source/version: http://cppreference.com Β· 2024.06.10 Β· page std::flat_map::try_emplace(3). Go forth and emplace responsibly. πŸ’…βœ¨

πŸ“¦ where this page comes from