Reputation: 5510
Why does the compiler expect separate specialization of a template on (concrete) types T
and const T
? Let me show an example. I had an unordered map keyed by a class type Key
std::unordered_map<Key, Value> data;
and for it to compile had to specialize std::hash
on the type Key
as
namespace std {
template<>
class hash<Key> { /* implementation */ };
}
However, when I changed the map type to
std::unordered_map<const Key, Value> data;
the compiler did not use my specialization and instead selected the generic std::hash<T>
, which is little more than a compile time assert, until I specialized std::hash<const Key>
.
Putting aside the utility of qualifying the map key type with const
, why does not const T
collapse to T
when looking for a specialization in this case?
Also, could the template class std::hash
(technically) be designed to allow such a collapse?
Upvotes: 4
Views: 609
Reputation: 241671
I can't really answer the "why", since it was a decision of the standards committee, who no doubt had their reasons.
The issue is not restricted to custom types. You can't instantiate std::unordered_map<const std::string, int>
either.
Of course, it is rarely if ever useful to use an explicit const
type as the key type of a standard associative container, since the value_type of the container is std::pair<const Key, Val>
; the key is const regardless of its declared type. But I understand that is not related to the original question, and the volatile
qualifier would have had the same effect.
Could it have been otherwise? Sure. It's not even that difficult:
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>;
The only difference is the use of std::remove_cv
in the default template argument for the Hash
template parameter.
Upvotes: 3