如何可移植地将 std::system_error 异常与 std::errc 值进行比较?

How to portably compare std::system_error exceptions to std::errc values?

据我所知,以便携方式检查 system_error 条件的最佳做法之一是将它们的 code() 值与 std::errc 枚举中的值进行比较.但是,当我尝试 运行 以下代码时,这似乎不起作用。

#include <cassert>
#include <cerrno>
#include <system_error>

int main() {
    try {
        throw std::system_error(ENOENT, std::system_category());
    } catch (std::system_error const & e) {
        assert(e.code() == std::errc::no_such_file_or_directory); // <- FAILS!?
    }
}

我是不是误解了这些诊断错误的工作原理,还是我做错了什么?应该如何比较 std::system_error 异常与 std::errc 值?

编辑: 代码似乎使用 clang++ 和 libc++ 正常工作,但在针对 libstdc++ 构建时失败,无论我使用哪个 GCC 或 Clang 编译器(和版本)采用。与 PR 60555 相关?任何便携式解决方法?

e.code() returns ::std::error_code 的一个实例,它重载了 operator ==,这导致 error_condition 对象隐式构造为 std::errc::no_such_file_or_directory。比较将失败,因为异常返回的 error_code 具有 system_category 而另一个将具有 generic_category。您应该与 error_code::value() 进行比较。请注意,此比较需要 std::errcstatic_cast 值,因为它是 enum class 并且不会隐式转换为 int。 Working example:

#include <cassert>
#include <cerrno>
#include <system_error>
#include <iostream>
 
int main()
{
    ::std::cout << static_cast< int >(ENOENT) << ::std::endl;
    ::std::cout << static_cast< int >(::std::errc::no_such_file_or_directory) << ::std::endl;
    try
    {
        throw std::system_error(ENOENT, std::system_category());
    }
    catch(::std::system_error const & e)
    {
        assert(e.code().value() == static_cast< int >(::std::errc::no_such_file_or_directory));
    }
}

你没有做错任何事。正如 T.C 在评论中所确认的那样。并在 , this is indeed caused by PR #60555。幸运的是,到 2018 年 8 月 8 日,这个错误已经在他们的 VCS 中得到修复:

Fixed on all active branches, so will be fixed in the 6.5, 7.4, 8.3 and 9.1 releases.

这似乎没有好的解决方法,所以现在只是 GCC 开发人员发布新版本的 GCC 的问题,并且在这些版本被纳入流行的发行版之前,我们最终可以开始使用这个不错的版本还需要几年的时间C++11 的现代特性。但这就是生活...