0

I'm trying to create a class with unordered_set of paths as data member. At first, I declared a class with this member and got error:

Attempting to reference a deleted function

After reading a few posts here as well as reading C++17 path class info, I understood I lacked specifying a hash function. So I tried this:

class A
{
public:
    A() = default;
    A(const A& fc) = default;
    A& operator=(const A& fc) = default;
private:
    std::unordered_set<fs::path, std::hash<fs::path>> m_files;
};

but still got the error above despite specifying the built-in hash function. (std::path also have operator= function)

Tried to instantiate an instance of this class, but got the error described. Seem related to the unordered set hash function.

Visual Studio 2019 (v142) 16.11.3 C++ Language standard: ISO C++20 standard (:/std:c++20) C Language standard: Default (Legacy MSVC)

What am I missing here?

  • Does this answer your question? [How to use unordered\_set with custom types?](https://stackoverflow.com/questions/9729390/how-to-use-unordered-set-with-custom-types) – cigien Apr 18 '23 at 14:19
  • You didn't change anything meaningful. You just explicitly written template parameter with type which is used implicitly if not provided. – Marek R Apr 18 '23 at 14:21
  • So when the compiler generates an error message, please include the ENTIRE error message (including any warnings before or after it) copy-pasted in your question. Not a screenshot, the actual text. While you might not understand the message, it does contain a description of what went wrong. – Yakk - Adam Nevraumont Apr 18 '23 at 14:21
  • Thank you all for commenting! Yakk- here is the error: Error C2208: 'std::_Uhash_compare<_Kty,_Hasher,_Keyeq>::_Uhash_compare(const std::_Uhash_compare<_Kty,_Hasher,_Keyeq> &)': attempting to reference a deleted function cigien- read this thread already Marek- OK. Other than that, what else should be added? – MorMordoch Apr 18 '23 at 14:24
  • @MorMordoch So if you work with your IDE, odds are you can get many many many more lines of errors than that. Figuring out how to access the other errors will help you in the future. – Yakk - Adam Nevraumont Apr 18 '23 at 14:25
  • 1
    Can't reproduce: https://godbolt.org/z/hGvP3c5ra https://godbolt.org/z/njE471Pr9 – Marek R Apr 18 '23 at 14:26
  • Please provide [mcve] remember specify: compiler, its version, build flags, platform. – Marek R Apr 18 '23 at 14:30
  • @MorMordoch the exact error details and all the other info should be in your question. Please [edit] it accordingly. – wohlstad Apr 18 '23 at 14:34
  • 1
    Real question is what is `fs`? If it is `std::filesystem` then it should just work out of the box. If it is something else then OP should specify this. – Marek R Apr 18 '23 at 14:37
  • @MarekR Visual Studio 2019 (v142) 16.11.3 C++ Language standard: ISO C++20 standard (:/std:c++20) C Language standard: Default (Legacy MSVC) Anything else is missing? (hopefully I provided what you asked) And yes: fs=std::filesystem – MorMordoch Apr 18 '23 at 16:41
  • Then it should work out of the box as show in links above. – Marek R Apr 18 '23 at 20:35
  • @MarekR The error is reproduced if I declare a simple void memeber function to insert a path to the unordered_set. Then, it won't compile. – MorMordoch Apr 23 '23 at 08:47

1 Answers1

1
std::unordered_set<fs::path, std::hash<fs::path>>

is equivalent to

std::unordered_set<fs::path>

in all ways. Saying std::hash<fs::path> is the same as not saying it.

What you need to do is provide a std::hash<fs::path>.

Personally I wouldn't specialize std::hash here, because you don't own fs::path; to future proof, I'd write my own hasher and pass it in. (the future proofing here is "the standard implements one, and now my code doesn't compile). Last I checked there was a badly worded requirement that your specializations in namespace std rely on a user defined type (it may have been fixed to be better worded), so it may even be illegal to define std::hash<fs::path>. I don't much care, because I consider it bad practice even if legal.

struct fs_path_hasher {
  std::size_t operator()(fs::path const& path)const {
    std::hash<fs::path::string_type> hasher;
    return hasher(path.native());
  }
};

now:

std::unordered_set<fs::path, fs_path_hasher> m_files;

should compile.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • He must have problem with compiler version since it just works with latest releases of compilers: https://godbolt.org/z/njE471Pr9 or `fs` is something else then I assumed. – Marek R Apr 18 '23 at 14:34
  • @MarekR Ah, I could see them adding `std::hash` and it not being in an early release of a `std` library. I also suspect my hasher is what the standard library implementation does on pretty much every platform (it is obvious and cheap), and there isn't anything fundamentally expensive about it. – Yakk - Adam Nevraumont Apr 18 '23 at 14:43
  • @Yakk-AdamNevraumont: Actually, you're not allowed to specify a `std::hash`. You cannot specialize any standard library template unless the specialization includes a type not in `std::`. – Nicol Bolas Apr 18 '23 at 16:45
  • @NicolBolas I figured. Last time I read that part of the standard, however, there was a defect (the term it seemed to intend to mean type not in `std` and not defined by the standard as a base type involved actually included types in `std`). I vaguely recall a defect was opened on the subject, so it probably got fixed. And it is a bad practice anyhow. – Yakk - Adam Nevraumont Apr 18 '23 at 17:17
  • Thank you, it worked. I'll read more about the hash stuff (I guess it has to implement operator()). If you have a recommended resource so I can read it too, will be highly appreciated. Again, thanks a lot! – MorMordoch Apr 20 '23 at 11:49
  • @MorMordoch cppreference is a good site to read – Yakk - Adam Nevraumont Apr 20 '23 at 14:55