Reputation: 451
I was wondering if it's possible to emplace a value into a vector that is stored in a map.
Currently I do this like so...
std::map<std::string, std::vector<std::string>> my_collection;
my_collection["Key"].push_back("MyValue");
I was thinking I could do the following and C++ would be smart enough to realize it should add it to the vector... but I get a memory compile error.
my_collection.emplace("Key", "MyValue");
Upvotes: 2
Views: 882
Reputation: 52357
You can create a vector, emplace into it, and then move the vector. This way your object will neither be copied or moved:
std::map<std::string, std::vector<std::string>> my_collection;
std::vector<std::string> temp;
temp.emplace_back("MyValue");
my_collection["Key"] = std::move(temp);
Alternatively, you create the vector in the map and work on a reference:
std::map<std::string, std::vector<std::string>> my_collection;
auto &keyVec = my_collection["Key"];
keyVec.emplace_back("MyValue");
Conveniently, this boils down to:
std::map<std::string, std::vector<std::string>> my_collection;
my_collection["Key"].emplace_back("MyValue");
Upvotes: 2
Reputation: 75727
No matter how smart C++ gets, it still has to respect the language rules and the public interfaces. std::map
does have an emplace
member. You need to use that.
The problem is that there is no way to construct a vector by moving elements into it (because of how std::initializer_list
is designed - don't get me started)
If you don't care about that and you can accept copying elements into the vector then all you need to do is:
auto test()
{
using namespace std::string_literals;
std::map<std::string, std::vector<std::string>> my_collection;
my_collection.emplace("key"s, std::vector{"MyValue"s});
}
The above will copy "MyValue"s
into a vector then will move the key and the vector into the map.
However if you do want moves or if you have move-only types then there is some extra work.
So I create a little utility function which does that: creates a vector by moving rvalues passed to it:
template <class... Args>
auto make_vector(Args&&... args)
{
using T = std::remove_reference_t<std::common_type_t<Args...>>;
static_assert((... && std::is_same_v<T, std::remove_reference_t<Args>>));
auto v = std::vector<T>{};
v.reserve(sizeof...(Args));
(..., v.emplace_back(std::forward<Args>(args)));
return v;
}
auto test()
{
using namespace std::string_literals;
std::map<std::string, std::vector<std::string>> my_collection;
my_collection.emplace("key", make_vector("MyValue"s));
}
Upvotes: 0