C++ 类型上的模板专门化和常量限定符

C++ 类型上的模板专门化和常量限定符,c++,c++11,C++,C++11,为什么编译器希望在(具体的)类型T和const T上分别专门化模板?让我举个例子。我有一个由类类型Key std::unordered_map<Key, Value> data; 但是,当我将贴图类型更改为 std::unordered_map<const Key, Value> data; std::无序的地图数据; 编译器没有使用我的专门化,而是选择了泛型的std::hash,它只不过是一个编译时断言,直到我专门化了std::hash 抛开使用const限定映射

为什么编译器希望在(具体的)类型
T
const T
上分别专门化模板?让我举个例子。我有一个由类类型
Key

std::unordered_map<Key, Value> data;
但是,当我将贴图类型更改为

std::unordered_map<const Key, Value> data;
std::无序的地图数据;
编译器没有使用我的专门化,而是选择了泛型的
std::hash
,它只不过是一个编译时断言,直到我专门化了
std::hash

抛开使用
const
限定映射键类型的实用程序不谈,在这种情况下,在查找专门化时为什么不将
const T
折叠为
T

另外,模板类std::hash(技术上)是否可以设计为允许这样的崩溃?

我不能真正回答“为什么”,因为这是标准委员会的决定,他们无疑有自己的理由

问题不限于自定义类型。您也不能实例化
std::无序映射

当然,使用显式
const
类型作为标准关联容器的键类型几乎没有用处,因为容器的值类型是
std::pair
;不管其声明的类型如何,键都是常量。但我知道这与原来的问题无关,
volatile
限定符也会有同样的效果

难道不是这样吗?当然其实也没那么难:

template<typename Key,
         typename Val,
         typename Hash  = std::hash<typename std::remove_cv<Key>::type>,
         typename KeyEq = std::equal_to<Key>,
         typename Alloc = std::allocator<std::pair<const Key, Val>>>
using my_unordered_map = std::unordered_map<Key, Val, Hash, KeyEq, Alloc>;
模板
使用my_unordered_map=std::unordered_map;
唯一的区别是在
Hash
模板参数的默认模板参数中使用了
std::remove_cv


()

仅仅是因为
T
const T
在定义上是不同的类型(除非
T
已经是
const
)<代码>标准::散列
可以设计成那样的折叠,是的,但显然不是这样。还是个好问题<代码>标准::无序映射也不会编译。因此,您不需要自定义密钥类型来注意问题。但是通常,在
std::{unordered}{multi,}map
中不需要使用显式的
const
类型,因为键总是
const
@rici:
字符串
键的优点!至于键类型的常数,我确实同意,但这不是我的重点。@kkm:明白。我把这个评论提升为一个答案;希望能有所帮助。如果您想要
std::unordered_map
,您可以始终明确地说明散列参数:
std::unordered_map
。答案中提出了一个更普遍的解决方案。
template<typename Key,
         typename Val,
         typename Hash  = std::hash<typename std::remove_cv<Key>::type>,
         typename KeyEq = std::equal_to<Key>,
         typename Alloc = std::allocator<std::pair<const Key, Val>>>
using my_unordered_map = std::unordered_map<Key, Val, Hash, KeyEq, Alloc>;