The standard says the following about specializing templates from the standard library (via What can and can't I specialize in the std namespace? )
A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited.
Is it legal to specialize standard library templates with a standard library class specialized with a user defined class?
For example, specializing std::hash
for std::shared_ptr<MyType>
?
From reading the above paragraph and linked question, it sounds like it should be, as the declaration of the specialization is dependent on MyType
, however "Unless explicitly prohibited" worries me slightly.
The example below compiles and works as expected (AppleClang 7.3), but is it legal?
#include <unordered_set>
#include <memory>
#include <cassert>
#include <string>
struct MyType {
MyType(std::string id) : id(id) {}
std::string id;
};
namespace std {
template<>
struct hash<shared_ptr<MyType>> {
size_t operator()(shared_ptr<MyType> const& mine) const {
return hash<string>()(mine->id);
}
};
template<>
struct equal_to<shared_ptr<MyType>> {
bool operator()(shared_ptr<MyType> const& lhs, shared_ptr<MyType> const& rhs ) const {
return lhs->id == rhs->id;
}
};
}
int main() {
std::unordered_set<std::shared_ptr<MyType>> mySet;
auto resultA = mySet.emplace(std::make_shared<MyType>("A"));
auto resultB = mySet.emplace(std::make_shared<MyType>("B"));
auto resultA2 = mySet.emplace(std::make_shared<MyType>("A"));
assert(resultA.second);
assert(resultB.second);
assert(!resultA2.second);
}
std::hash
except DefaultConstructible, CopyAssignable, Swappable and Destructible (and all other requirements that has nothing to do with "explicitly prohibited"). One example of "explicitly prohibited" specialization is specializingstd::numeric_limits
for non-arithmetic standard types. – Holt