unordered_set of std::filesystem::path as a data member

228 Views Asked by At

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?

1

There are 1 best solutions below

6
Yakk - Adam Nevraumont On

Assuming namespace fs = std::filesystem;

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.