std::unordered_set<std::filesystem::path>:v.12 以下的 clang 和 g++ 上出现编译错误。 Bug 还是用户错误?

问题描述 投票:0回答:2

我将以下函数模板添加到我的项目中,用户抱怨它无法再在他们的系统上编译:

template<typename T>
std::size_t removeDuplicates(std::vector<T>& vec)
{
    std::unordered_set<T> seen;

    auto newEnd = std::remove_if(
        vec.begin(), vec.end(), [&seen](const T& value)
        {
            if (seen.find(value) != std::end(seen))
                return true;

            seen.insert(value);
            return false;
        }
    );

    vec.erase(newEnd, vec.end());

    return vec.size();
}

带有

g++ 9.4
的错误消息大约为

error: use of deleted function
'std::unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set() 
[with
_Value = std::filesystem::__cxx11::path; 
_Hash = std::hash<std::filesystem::__cxx11::path>; 
_Pred = std::equal_to<std::filesystem::__cxx11::path>; 
_Alloc = std::allocator<std::filesystem::__cxx11::path>]'
   12 |  std::unordered_set<T> seen;

所以用

T = std::filesystem::path
实例化上面的函数模板时就出现了错误。 我调查了一下,发现用其他类型实例化它时没有问题,例如基本类型或
std::string
,但仅限于
std::filesystem::path

使用 Compiler Explorer,我查看了不同编译器版本如何处理代码,发现只有

g++ v.12
可以用
std::filesystem::path
编译实例化。任何低于 12 的
g++
版本都会失败并出现上述错误。即使在最新版本 (14) 上,
clang
也会产生类似的错误 (
call to implicitly deleted default constructor
)。我没有测试其他编译器。

我使用的解决方法是将

std::unordered_set
替换为
std::set
。然后它适用于
g++ v.8
clang v.7
及以上。

所以我猜错误是缺少

std::filesystem::path
的哈希函数?还是我的失误?

c++ g++ c++17 clang std-filesystem
2个回答
4
投票

std::hash
std::filesystem::path
专业化最近才作为 LWG 问题 3657 的决议添加到标准草案中。它在已发布的 C++17 和 C++20 标准中尚未出现。

然而,一直有一个函数

std::filesystem::hash_value
,您可以轻松地创建一个函数对象以作为哈希函数传递给
std::unordered_set

struct PathHash {
    auto operator()(const std::filesystem::path& p) const noexcept {
        return std::filesystem::hash_value(p);
    }
};

//...

std::unordered_set<std::filesystem::path, PathHash> seen;

如果您提供的模板没有任何保证它适用于定义了

std::hash
专业化的类型以外的类型,那么我认为您没有问题。

但是,如果您要求类型可散列,那么让用户以与

std::unordered_set
相同的方式覆盖散列函数将是一个好主意。这同样适用于所使用的等式函子。


0
投票

补充一下std::hashstd::filesystem::path是在C++17中添加的答案,它实际上是在以下版本的标准库中实现的:

C++ 标准库 版本
GCC libstdc++ v11.4
Clang libc++ 17
MSVC STL 19.32

来源:CPP 参考 C++17 编译器支持

© www.soinside.com 2019 - 2024. All rights reserved.