You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

std::unordered_set<std::filesystem::path>在旧GCC/Clang编译失败:Bug还是用户错误?

问题

我在项目中添加了如下函数模板,有用户反馈在他们的系统上无法编译:

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会报错。

通过测试不同编译器版本后发现,只有g++ v.12能成功编译该实例化,所有低于v12的GCC版本都会报上述错误;即使是最新版本(14)的Clang也会产生类似错误(call to implicitly deleted default constructor)。

我采用的临时解决方法是将std::unordered_set替换为std::set,此时在g++ v.8及Clang v.7以上版本均可正常编译。

请问该错误是因为缺少std::filesystem::path的哈希函数导致的,还是我的代码存在问题?

回答

这个错误的核心原因是标准库对std::filesystem::path的哈希函数支持存在版本差异,你的代码本身没有问题。

具体细节:

  • C17标准引入std::filesystem::path,但直到C20才强制要求标准库提供std::hash<std::filesystem::path>的特化实现。在此之前,不同编译器的支持情况不一致:
    • GCC在v12及以上版本才默认提供该哈希特化;低于v12的版本中,std::hash<std::filesystem::path>要么未定义,要么被标记为删除,导致依赖它的std::unordered_set<T>无法默认构造。
    • Clang至今(v14)仍未默认提供该哈希特化,因此会触发类似错误。

改用std::set能正常编译的原因是:std::set依赖的是std::less<T>(即<运算符),而std::filesystem::path从C17开始就支持<运算符重载,所以在符合C17标准的编译器版本中都能正常工作。

如果想继续使用std::unordered_set兼容旧编译器,有两个可选方案:

  1. 为std::filesystem::path自定义哈希函数,显式传递给std::unordered_set:
struct PathHash {
    std::size_t operator()(const std::filesystem::path& p) const {
        return std::hash<std::string>{}(p.string());
    }
};

// 使用时指定哈希函数
std::unordered_set<std::filesystem::path, PathHash> seen;
  1. 升级编译器到GCC v12及以上版本,利用标准库提供的哈希特化。

内容的提问来源于stack exchange,提问作者RL-S

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 17:09:32