为什么std::set中同时存在key_type与value_type两种类型定义?
为什么std::set同时定义了相同的key_type和value_type?
这是C++标准库为了统一所有关联容器的接口规范特意设计的,并不是冗余定义,核心价值体现在泛型编程的通用性上:
- 对齐所有关联容器的接口约定
C++标准把std::set、std::map、std::multiset、std::multimap都归为关联容器类别,要求所有这个类别的容器都必须提供key_type(键的类型)、value_type(容器存储元素的类型)这两个成员类型。对于std::map这类键值分离的容器,二者的区别非常明确:比如std::map<int, std::string>的key_type是int,value_type是std::pair<const int, std::string>。而std::set的特性是存储的元素本身就是排序用的键,所以才会出现key_type和value_type完全一致的情况,只是统一接口下的特殊场景,不是多余设计。 - 避免泛型代码做不必要的特化适配
如果所有关联容器都有统一的成员类型定义,写泛型逻辑的时候就不需要为std::set单独做分支处理,一套代码可以兼容所有关联容器。举个简单的例子:
// 通用的键存在性校验模板,同时支持所有关联容器 template <typename AssociativeContainer> bool has_key(const AssociativeContainer& container, const typename AssociativeContainer::key_type& key) { return container.find(key) != container.end(); } // 不用做任何修改,既可以传入std::set,也可以传入std::map std::set<int> num_set = {1,2,3}; has_key(num_set, 2); // 正常编译运行 std::map<int, std::string> num_map = {{1, "one"}, {2, "two"}}; has_key(num_map, 2); // 同样正常编译运行
如果std::set删掉了其中一个类型定义,上面这种通用泛型代码就无法兼容std::set,必须单独写特化版本,反而会大大增加泛型代码的开发和维护成本。
- 保证历史代码的向后兼容性
这套接口规范从C++98标准发布起就已经确定,二十多年来有大量现有代码依赖std::set的这两个成员类型做编译期类型推导、校验,如果标准直接删掉其中一个,会导致海量的历史代码无法编译,这是标准绝对不会做的破坏性变更。
内容的提问来源于stack exchange,提问作者Yves
相关产品推荐
相关产品推荐

