为何std::map未添加适配透明比较的operator[]()模板重载?
你注意到的std::map的两个operator[]重载:
T& operator[]( const Key& key ); // (1) T& operator[]( Key&& key ); // (2)
它们的核心语义是键不存在时插入默认构造的对应值,这决定了无论传入什么类型的参数,只要触发插入逻辑,就必须构造出Key类型的对象存入容器。而你提议的模板重载:
template <typename K> T& operator[](K&& key); // (3)
之所以没有被标准引入,主要有以下几个原因:
语义冲突与必要性缺失
透明比较器的作用是允许用可与Key比较的任意类型查找,但operator[]的本质是“查找或插入”,插入行为必然需要构造Key。如果传入的K不是Key类型,即便比较器能匹配,只要键不存在,还是得从K构造Key——这并没有避免Key的构造,只是把构造时机从参数传递延后到插入时。而如果只是想查找不插入,std::map::find()已经支持透明比较器,完全可以用它来实现无构造的查找,不需要修改operator[]。重载决议的歧义风险
添加模板化的K&&重载后,会和现有重载(2)产生歧义。比如当传入Key类型的右值时,重载(2)是精确匹配,重载(3)会推导为K=Key,同样是精确匹配,编译器无法决议选择哪一个。要让它仅在透明比较器时生效,需要用SFINAE(比如std::enable_if_t<std::is_transparent_v<typename Compare>>)来约束,但这会大幅增加接口的复杂度,不符合标准库“简洁核心接口”的设计原则。标准委员会的权衡
C++标准库的扩展需要兼顾兼容性、实现复杂度和实际收益。这个重载的场景已经被find()覆盖,且引入后会带来重载歧义、语义混淆等问题,实际收益远小于维护成本。标准委员会更倾向于保持operator[]的语义清晰——明确它是“查找并插入”的工具,而把无插入的查找需求交给find()。
内容的提问来源于stack exchange,提问作者LoS

