【问题标题】:Why does std::make_error_code(std::errc) exist?为什么 std::make_error_code(std::errc) 存在?
【发布时间】:2021-10-27 17:49:46
【问题描述】:

我了解std::error_codestd::error_condition 之间的区别,并且我了解std::errc 是“错误条件”枚举而不是“错误代码”枚举。我了解如何将结果 std::error_code 值与“错误条件”等进行比较。这些年来,我多次阅读Chris Kohlhoff's blog post about these types。我已经在生产代码中使用了这些类型和它们的扩展。

但是,我不明白为什么std::make_error_code(std::errc) 存在。

似乎没有必要比较实际std::error_code 值与std::error_condition 值:有std::make_error_condition(std::errc) 和到std::error_condition 的转换以及所有这些的特殊比较重载.

函数的存在尤其令人费解,因为std::is_error_code_enum_v<std::err>false 对应于std::errc。大概是防止通过std::make_error_code(std::errc)std::errc隐式转换为std::error_code,但我不清楚为什么std::make_error_code(std::errc)时阻止这是可取的存在。换句话说,如果您不应该从std::errc 中创建std::error_code,那么为什么会有一个函数可以做到这一点?如果你应该这样做,为什么禁用隐式构造函数?

std::errc 是否是一个特殊情况,因为代码通常希望在 std::generic_category() 中实际生成一个具有 std::errc 值的真实 std::error_code?换句话说,std::errc 在某些方面 both 是“错误代码”和“错误条件”枚举吗? (如果是这样,为什么不是std::is_error_code_enum_v<std::errc> true?)

是不是因为其他原因的特殊情况?

用户定义的错误条件枚举是否也应该像 std::errc 那样提供 make_error_code(),还是只提供 make_error_condition()

【问题讨论】:

    标签: c++ error-code


    【解决方案1】:

    std::errc 定义可移植错误的值;一组简单的(事实上,非常有限的)错误代码值。

    std::error_code 是一个依赖于平台的错误,它包含一个错误代码值和对错误类别对象的一个​​对象的引用。


    从程序设计的角度来看,只是没有充分的理由将std::errc隐式转换为std::error_code。它们在逻辑上非常不同的错误集: 简单与分类(来源) 标准错误集与环境(平台和标准库实现)相关的错误集。

    代码之间的转换不仅仅是改变类型或数字表示,它通常是依赖于环境的逻辑。

    这种转换的非成员函数是一种非常自然的解决方案。


    从实施方面, 它们不是基本类型,因此编译器会专门支持类型之间的转换; std::errc 实现为class enum 枚举,不能像类那样实现转换运算符函数; std::error_code 是一个类,因此可以实现来自 std::errc 的非显式构造函数,它支持隐式转换,就像 std::io_errcstd::future_errc (*) 一样,但在逻辑上对应不同的错误集这不是std::error_code 关心的问题,它会违反面向对象编程的原则(具体来说,这将是对代码实体的不适当的责任分配)。


    (*) - std::io_errcstd::future_errc (以及其他 error code enumerations 具有)可以隐式转换为 std::error_code 因为它们与 std::error_code 存储的错误相同 - std::error_code 存储相同的错误代码值和对错误对象对应类别的引用;错误集只是 std::error code 支持存储的整个集的子集。


    隐式转换只会使程序设计变得更糟且容易出错(具体而言,代码的责任分配不合逻辑,并且容易发生隐蔽和不希望的转换)。

    【讨论】:

    • error_code 通过模板化构造函数(包括std::io_errcstd::future_errc)从其他专门针对is_error_code_enum<T> 的枚举类型进行隐式转换,每个类型都使用make_error_code() 重载。上面的答案似乎是基于这样的转换无法实现且不存在的前提,事实并非如此,所以我认为它不能回答我的问题。我问(除其他外)为什么 errc 有一个 make_error_code(),然后 not 可供此模板化隐式转换 error_code 构造函数使用。
    • @BradSpencer,我不确定你为什么在评论中隐含std::make_error_code 调用转换。这不是 C++ 中所谓的 implicit conversionen.cppreference.com/w/cpp/language/implicit_conversion。在您的问题中,您问为什么std::error_code 中没有构造函数接受std::errc(以便隐式转换),我回答了您的问题。
    • 来自 en.cppreference.com/w/cpp/error/error_code/error_code 的构造函数 3 是从“错误代码枚举”类型(is_error_code_enum 为真)的隐式转换。这是根据您的链接和en.cppreference.com/w/cpp/language/converting_constructor 转换构造函数的单参数非显式构造函数。我的问题是“为什么std::make_error_code(std::errc) 存在?”。不是“为什么error_code 上没有构造函数接受errc?”
    • @BradSpencer,您在问题正文中写道“为什么禁用隐式构造函数?” 这正是std::error_code 接受@ 的非显式构造函数987654359@。函数std::make_error_code(std::errc) 之所以存在是因为它很有用。这里没有隐式转换,因为它只会使程序设计在逻辑上更糟糕并且容易出错。 [看下一条评论...]
    • [...continuation:] std::io_errcstd::future_errc(以及其他 error code enumerations 具有)可以隐式转换为 std::error_code,因为它们只是与 std::error_code 相同的错误store - std::error_code 存储完全相同的错误代码值和对错误对象对应类别的引用;错误集只是std::error code 支持存储的整个集的子集。 [看下一条评论...]
    猜你喜欢
    • 2019-01-03
    • 2018-12-03
    • 1970-01-01
    • 1970-01-01
    • 2020-01-21
    • 2022-03-27
    • 1970-01-01
    • 2020-12-23
    • 2020-10-29
    相关资源
    最近更新 更多