Yes, it is legal.
At some point, it is even dubious to specialize in std::shared_ptr<int> ; I do not know if they corrected this ambiguity in the standard as a defect or not.
Note that this is a poor hash implementation for global use. Firstly, because it does not support null common pointers. Secondly, since hashing a common pointer, as always, the value of int is doubtful. This is even dangerous, because if a generic pointer to an int in the container has this int change, you just broke the program.
Think about how to create your own hash for such cases.
namespace notstd { template<class T, class=void> struct hasher_impl:std::hash<T>{}; namespace adl_helper { template<class T> std::size_t hash( T const& t, ... ) { return ::notstd::hasher_impl<T>{}(t); } }; namespace adl_helper2 { template<class T> std::size_t hash_helper(T const& t) { using ::notstd::adl_helper::hash; return hash(t); } } template<class T> std::size_t hash(T const& t) { return ::notstd::adl_helper2::hash_helper(t); } struct hasher { template<class T> std::size_t operator()(T const& t)const { return hash(t); } }; }
Now it allows 3 settings.
First, if you override std::size_t hash(T const&) in the namespace containing T , it selects it.
Otherwise, if you specialize in notstd::hasher_impl<T, void> for your type T , it selects it.
Thirdly, if both of them do not work, it calls std::hash<T> , picking up any specializations.
Then you can do:
std::unordered_set<std::shared_ptr<MyType>, ::notstd::hasher> mySet;
and add:
struct MyType { MyType(std::string id) : id(id) {} std::string id; friend std::size_t hash( MyType const& self) { return ::notstd::hash(self.id); } friend std::size_t hash( std::shared_ptr<MyType> const& self) { if (!self) return 0; return ::notstd::hash(*self); } };
which should give you a smart hash on shared_ptr<MyType> .
This prevents the danger of someone changing the id to shared_ptr<MyType> , which splits each container containing shared_ptr<MyType> non-local way.
General condition is the devil; consider writing a copy on the record pointer if you are really worried that it is expensive.