In c++17 first, I have a struct like
typedef struct ST_A{
int a;
string s;
ST_A(const int a, const string&s) :a(a),s(s) {}
}st_A;
And Now I have a simple map and emplace twice in terms of cppreference
map<string, st_A> m1;
m1.emplace("c", 10, "c"); ---> case 1
m1.emplace(std::piecewise_construct, ---> case 2
std::forward_as_tuple("c"),
std::forward_as_tuple(10, "c"));
Case 2 works fine but case 1 compiles in error. So how to solve it in case 1 and make emplace as concise as possible?
What if the map is much more complex? Like
map<string, deque<pair<int, st_A>>> m2, how to emplace it as concise as possible?
What if self-define struct has more constructors?Like
typedef struct ST_A{
int a = 0;
string s;
ST_A(const int a) :a(a) {}
ST_A(const string&s) :s(s) {}
ST_A(const int a, const string&s) :a(a),s(s) {}
}st_A;
would it confuse the compiler if there actually is some consice way to emplace as the above link in cppreference.
UPDATE
If my original map is map<string, deque<pair<int, st_A>>> m2, and now I want to add an element of pair{"c1", pair{1, st_A{10, "c"}}}.That is to say, after adding, m2 changes into map{{"c1",deque{pair{1,st_A{10, "c"}}}}
with the form of insert codes is like
m2.insert({"c1", {{1, {10, "c"}}}});
but it may call too many ctor/copy ctor, if I want to write in a more efficient way in performance, how could it be?
emplace()constructsstd::pair<const Key,Value>from the passed arguments.Without
std::piecewise_construct, you have to pass exactly two arguments, one to construct the key, one to construct the value:Which defeats the purpose of "emplacing" since you are constructing the value ahead of the call.
My recommendation is to use
try_emplacewhich has a more friendly API, especially if the key is simple and allows exactly what you want:In general, the first argument constructs the key, the rest construct the value.
Keyctor can thus be omitted if it accepts just one argument.The return value indicates whether the element has been
insertedor if there is already an element with the same key present.itreturns basicallym1.at("c").The key is always constructed, the value arguments are only "consumed"(=moved from) if
inserted==true. Otherwise they are untouched.Example
For
map<string, deque<pair<int, st_A>>> m2;, you could the the following:std::dequedoes not have a constructor that accepts a single element, aggregate initialization does not work either. Not that it would save any copies,std::deque::emplace_backachieves that already. Som2["C"]does the construction efficiently already.If you want to also elide
st_Atemporary, you can again fallback tostd::pair'sstd::piecewise_construct: