I have a std::map<CompositeKey, std::string>
, where CompositeKey
is a class I wrote.
This CompositeKey
has three int
data members, all the constructors, all the copy assignment operators and a friend bool operator<
, which compares the sum of the three data members.
I understood how to use emplace
and emplace_hint
.
For example:
// emplace
std::map<CompositeKey, std::string> my_map;
int first_id = 10, second_id = 100, third_id = 1000;
std::string my_string = "foo";
auto [ insertedIt, success ] = my_map.emplace(std::piecewise_construct,
std::forward_as_tuple(first_id, second_id, third_id),
std::forward_as_tuple(my_string));
// emplace_hint
first_id = 5, second_id = 50, third_id = 500;
my_string = "bar";
std::tie(insertedIt, success) = my_map.emplace_hint(insertedIt
std::piecewise_construct,
std::forward_as_tuple(first_id, second_id, third_id),
std::forward_as_tuple(my_string));
The only way I was able to use try_emplace
was in the version without hint:
first_id = 1, second_id = 10, third_id = 100;
my_string = "foobar";
std::tie(insertedIt, success) = my_map.try_emplace({first_id, second_id, third_id},
my_string);
My questions are:
try_emplace
, without hint? If not, how could I call it?try_emplace
version with a hint? I made some attempts but always failed.try_emplace
"move" or "copy" the CompositeKey inside the map? I am asking about the behaviour of try_emplace
both because I read something similar on another discussion, and because I wrote a verbose copy and move constructors to make a test.I am sorry, I made my research but do not understand these points from the cppreference documentation
I think you may be misunderstanding the cppreference documentation. In your code, you are always trying to add a key that is not in the map. And you are passing that key as an lvalue reference. The only difference with your two cases is that you are using a hint in the second call. So the two try_emplace
versions you are using, according to cppreference, are 1 and 3.
template< class... Args > pair<iterator, bool> try_emplace( const Key& k, Args&&... args ); (1) (since C++17) template< class... Args > iterator try_emplace( const_iterator hint, const Key& k, Args&&... args ); (3) (since C++17)
Notice:
Key&
).pair<iterator, bool
, but second version just returns an iterator
.Now, the text below doesn't tell how you have to build your try_emplace
arguments; instead, it says what try_emplace
is doing internally.
1) If a key equivalent to k already exists in the container, does nothing. Otherwise, behaves like emplace except that the element is constructed as value_type(std::piecewise_construct, std::forward_as_tuple(k), std::forward_as_tuple(std::forward<Args>(args)...))
In short, just call try_emplace
passing a CompositeKey
object and a string as arguments (and, optionally, an iterator as a hint). The code below calls try_emplace
with an lvalue and an rvalue (the second call with a hint), so it would use the versions 1 and 4.
std::map<CompositeKey, std::string> my_map;
std::cout << "Case 1:\n";
auto key1{CompositeKey{10, 100, 1000}};
auto value1{std::string{"foo"}};
auto [insertedIt, success] = my_map.try_emplace(key1, value1);
std::cout << "Case 2:\n";
insertedIt = my_map.try_emplace(insertedIt, {5, 50, 500}, "bar");
// Outputs:
//
// Case 1:
// custom ctor
// copy ctor
// Case 2:
// custom ctor
// move ctor
- Is it correct to assume that try_emplace "move" or "copy" the CompositeKey inside the map?
Whatever you pass is forwarded to try_emplace
implementation. In the example above, both CompositeKey
arguments are first "custom constructed" ; then, they are passed to try_emplace
, where the lvalue is copy constructed while the rvalue is move constructed.