I want to insert key value pairs into a std::map
with uint32_t
as the key type and a custom type for values. Based on the documentation of std::map
, I wrote the following code:
#include <cstdint>
#include <iostream>
#include <map>
struct Values
{
uint32_t a = 0;
uint32_t b = 0;
Values(uint32_t _x, uint32_t _y): a(_x), b(_y)
{
std::cout << __func__ << "(" << _x << ", " << _y ")" << std::endl;
}
};
int main()
{
std::map<uint32_t, Values> data;
for(uint32_t i = 0; i < 100; i++)
data.emplace(i, std::forward_as_tuple(i, i));
return 0;
}
I'm compiling the code with gcc
by running
gcc -O3 -std=c++23 -Wconversion -Wall -Wextra -Wpedantic -fanalyzer
However, this code doesn't compile.
Here's the link to compiler explorer where you can see the full output of gcc
.
gcc
is complaining about:
error: no matching function for call to 'construct_at(std::pair<const unsigned int, Values>*&, unsigned int&, std::tuple<unsigned int&, unsigned int&>)'
Why am I getting this error and how can I fix this?
std::map<uint32_t, Values> data; data.emplace(i, std::forward_as_tuple(i, i));
emplace()
tries to construct the map's value_type
(i.e. pair<uint32_t, const Values>
) using the bag of arguments you passed to emplace()
. So, it's going to be trying to do this:
auto kv = pair<uint32_t, const Values>(i, std::forward_as_tuple(i, i));
That's not right. If you're trying to use pair
's perfect-forwarding constructor, you need to say instead:
auto kv = pair<uint32_t, const Values>(
std::piecewise_construct,
std::forward_as_tuple(i), // args for the first element
std::forward_as_tuple(i, i) // args for the second element
);
which means your emplace()
call needs to look like:
data.emplace(
std::piecewise_construct,
std::forward_as_tuple(i), // args for the first element
std::forward_as_tuple(i, i) // args for the second element
);
Alternatively, if you don't mind constructing the Values
a little earlier, you can just write:
data.emplace(i, Values(i, i));
which corresponds to:
auto kv = pair<uint32_t, const Values>(
i, // first element
Values(i, i) // second element
);
Or even:
data.insert(std::make_pair(i, Values(i, i)));