C++17中如何让map.emplace自动选构造函数及高效使用?
C++17下map相关emplace与高效插入问题解答
1. 修复并简化map<string, st_A>的emplace写法(原case1)
原case1编译失败的核心原因:map的emplace需要构造pair<const string, st_A>,而emplace("c",10,"c")试图传递3个参数给pair的构造——但pair没有接受3个参数的构造函数,无法自动将后两个参数转发给st_A的构造。
最简洁的修复写法:
m1.emplace("c", {10, "c"});
利用C++17的列表初始化,让pair的第二个参数直接通过列表构造st_A,无需显式写出st_A类型(前提是st_A的构造函数非explicit,原代码符合要求)。
如果需要更明确(比如避免潜在歧义),也可以显式构造:
m1.emplace("c", st_A{10, "c"});
2. 复杂容器map<string, deque<pair<int, st_A>>>的简洁emplace写法
对于嵌套容器,结合C++17的类模板实参推导和列表初始化,最简洁的写法是:
map<string, deque<pair<int, st_A>>> m2; m2.emplace("c1", deque{{1, {10, "c"}}});
编译器会自动推导嵌套的deque、pair和st_A类型,无需全部显式声明。
3. 多构造函数下的简洁emplace是否会导致编译器混淆
当ST_A存在多个构造函数时,明确的列表初始化不会导致混淆:
m1.emplace("c", {10}):匹配ST_A(const int)构造函数m1.emplace("c", {"str"}):匹配ST_A(const string&)构造函数m1.emplace("c", {10, "str"}):匹配ST_A(const int, const string&)构造函数
但如果存在参数类型重叠的构造函数(比如ST_A(long)和ST_A(int)),或者列表参数能匹配多个构造函数,会出现编译错误。此时显式指定st_A的构造即可避免歧义:
m1.emplace("c", st_A{10}); // 明确调用int版本构造
4. 高效插入map<string, deque<pair<int, st_A>>>的写法
原insert写法会产生多个临时对象,触发多次构造/拷贝。要实现最高效的插入,需直接在容器内存中构造所有嵌套元素,避免临时对象:
最优方案:try_emplace + 嵌套emplace_back
try_emplace会先检查键是否存在,不存在才构造值对象,完全避免临时开销:
auto [it, inserted] = m2.try_emplace("c1"); if (inserted) { // 直接在deque中构造pair和st_A,无临时对象 it->second.emplace_back( std::piecewise_construct, std::forward_as_tuple(1), std::forward_as_tuple(10, "c") ); }
简化高效写法(确定键不存在时)
如果能确定键"c1"不存在,也可以一步完成:
m2.emplace("c1", deque<pair<int, st_A>>{}) .first->second.emplace_back(1, st_A{10, "c"});
或者进一步简化列表初始化:
m2.emplace("c1", deque{{1, {10, "c"}}});
C++17编译器会优化掉临时对象,效率接近直接构造。
内容的提问来源于stack exchange,提问作者f1msch
相关产品推荐
相关产品推荐

