1

I have a class template C<B> which inherits from std::string, and I want to make it hashable like a normal std::string. I have written the following code, and it compiles.

I wonder if it is the correct implementation. Since a cast from derived class to base class may truncate memory, I wonder if it will cost too much?

#include <unordered_set>
#include <string>

template <bool B>
struct C : std::string
{
    C(std::string s) : std::string(s) {}
};

namespace std {

    template <bool B>
    struct hash<C<B>>
    {
        std::size_t operator()(const C<B> &k) const {
            return std::hash<std::string>()(static_cast<std::string>(k));
        }
    };

} // namespace std

int main() {
    std::unordered_set<C<false>> s;
    std::string c = C<false>("a");
    s.insert(c);
    return 0;
}
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
calvin
  • 2,125
  • 2
  • 21
  • 38
  • 7
    A side note: it's usually not recommended to inherit std types like `std::string`. See: https://stackoverflow.com/questions/6806173/subclass-inherit-standard-containers. – wohlstad Jun 12 '23 at 13:26
  • `C` has no members, there is nothing to be truncated. – 463035818_is_not_an_ai Jun 12 '23 at 13:45
  • The constructor should be rewritten to `C(std::string s) : std::string(std::move(s)) {}` to avoid an extra memory allocation. – fabian Jun 12 '23 at 17:54

1 Answers1

6

Yes, the implementation will work, but static_cast<std::string>(k) is not needed - and will create a temporary std::string which you probably would like to avoid.

If you instead make it static_cast<const std::string&>(k), it will not create a temporary std::string. Same thing if you simply do:

std::size_t operator()(const C<B>& k) const {
    return std::hash<std::string>()(k);
}
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • Hi, thx for your answer, it works. However, in the mean time I came up with another idea with `string_view`, it also compiles, I wonder if it is also a good way to solve this? – calvin Jun 13 '23 at 09:42
  • @calvin You're welcome! Using a `std::string_view` inside the `std::hash::operator()` will have no benefit as I can see it. It just creates a `string_view` and hashes that instead of the string - but the algorithm is most likely the same. It is in all implementations I've looked at. – Ted Lyngmo Jun 14 '23 at 06:49