为什么std :: map并不总是允许兼容类型作为其键类型?

时间:2016-12-28 04:09:19

标签: c++ stl c++14 standards

#include <map>
#include <string>
#include <string_view>

using namespace std;

int main()
{
    string_view key = "hello";      
    map<string, int, less<>> coll;
    coll.find(key); // ok
    coll[key] = 0;  // !!! error ???
}

密钥类型为std::string,兼容类型为std::string_view。从C ++ 14开始,std::map::find允许使用兼容密钥;所以coll.find(key);没问题。

然而,为什么不 coll[key] = 0; 也可以?

2 个答案:

答案 0 :(得分:4)

coll.find(key)只需key与实际密钥类型进行可比较std::string_viewstd::string相当。但是,为了能够将key插入collkey需要可兑换std::string,而不是{{1}} ,无论如何)。

答案 1 :(得分:3)

N3465中描述了背后的基本原理。

  

从概念上讲,扩展包括基于严格的弱排序替换原始公式,其中一个依赖于序列划分的概念,正如David Abrahams首先提出的那样。不幸的是,这个扩展过程还没有针对关联容器的查找操作进行,关联容器仍然是根据严格的弱顺序制定的,因此不允许异构   比较。

从N3465获取此示例,并稍微修改一下:

struct name_entry
{
    std::string family_name;
    std::string given_name;
};
auto as_tuple(const name_entry& e)
{
     return std::tie(e.family_name, e.given_name);
}
bool operator<(const name_entry& x, const name_entry& y)
{
    return as_tuple(x) < as_tuple(y);
}
bool operator<(const name_entry& x, const std::string& y) 
{
    return x.family_name<y;
}
bool operator<(const std::string& x, const name_entry& y) 
{
    return x<y.family_name;
}
int main()
{
    std::set<name_entry, std::less<>> names;
} 

发明异构比较是为了找到满足部分比较的包含对象,比如发现某人有一个姓氏。

另一方面,

operator[]将构造value_type如果找不到key,则必须在此操作中应用严格的弱排序,因此不能应用异构比较