std::errc,如何在 retval 中表示成功



我想写一个这样的 c++ 函数:

#include <system_error>
std::errc f() { return std::errc::success; }

但是我不明白如何使用 std::errc 'enum class' 类型返回一个成功的值(在本例中为 0)。我看到的一种方法是返回 int:

template <typename E>
constexpr typename std::underlying_type<E>::type to_underlying(E e) {
    return static_cast<typename std::underlying_type<E>::type>(e);
}
int f() { is_succ() ? 0 : to_underlying(err); }

但对我来说看起来很丑。从 std c++ 0x14中的函数返回面向 C 的成功/错误代码的标准方法在哪里?

附言。我正在使用 MS VC 2015 补丁 2。

你可以

这样做:

#include <system_error>
std::errc f() { return std::errc(); }
int main()
{
    std::errc x = f();
    if (x == std::errc())
    {
        // success
    }
}

std::errc() (0) 是有效的枚举值,即使它未出现在从 1 开始的枚举器列表中。它代表着成功。

为了进行比较,请查看 std::to_chars,它返回

struct to_chars_result {
    char* ptr;
    std::errc ec;
}

通常不会直接从函数返回std::errc值。 相反,您返回一个std::error_code 。 例如,您的函数将像这样声明:

std::error_code f();

然后,将该函数的结果与 std::errc 值进行比较。 例如:

std::error_code error = f();
if (error == std::errc::no_such_file_or_directory)
{
  // deal with the error
}

std::error_code是上下文可转换的布尔值。 测试函数是否成功的方法是在布尔表达式中使用错误代码。 例如:

std::error_code error = f();
if (error)
{
  // the function failed...
}

要从此类函数返回成功,请返回默认的初始化std::error_code。 例如:

std::error_code f()
{
  // do stuff...
  return std::error_code{}; // success!
}
此方法在使用

C 样式 API 时非常有效。 包装器将使用 API 返回的整数值和定义如何将这些错误转换为std::errc值的自定义std::error_category构造std::error_code对象。

然而,相反的情况是行不通的。 如果你正在为C++库编写一个 C 包装器,那么你必须用 C 的方式做事。 使用错误值定义一个enum,并从 C 入口点返回这些值。

人们可能会想象一个快速(和肮脏)的答案:

// default category is std::system_error
inline std::error_code system_error_code_default{};

您可能会创建系统错误的全局默认实例,其内部值确实为 0(零),这是"成功的标志"。然后你用它来"表示一个好的 retval"

std::error_code very_complex_operation ()  
{
  return {};
   // same as
  // return error_code_success ;
}

然后您可以在返回时检查是否成功

    auto errcde = very_complex_operation();
    auto default_category_name = errcde.category().name();
    if (system_error_code_default == errcde) {
      // the sucess 
    }  else {
      // error condition
    }

这确实会起作用,您不必"做任何其他事情"。但。这在逻辑上都发生在"系统"错误类别(又名域)中。

    // "system"
    auto default_category_name = errcde.category().name();

因此,您在这里处于"系统"错误的领域。如果这是你想要的,好吧。但我对此表示怀疑。在"玩"上述内容之后,您将立即需要定义自己的 std::error_code 系统,使用您自己的枚举、类别、消息和其他内容。仅与您的 API 相关的信令错误。

要理解为什么在存在多个错误类别的情况下,只需考虑 std::error_code 使用模式。了解 std 命名空间就是这样做的。其中至少有三类。

您的用户/客户端可能正在编写一个C++应用程序,其中可能有十几个或更多不同的库。如果您使用自己的标准 std::error_code 系统开发 API,使用起来会感觉"正常"。用户将能够并且可能愿意将您的API集成到他们的程序中。

我希望这能更全面地回答这个问题。如果您希望按照自己的错误代码(以及更多)的方向继续,请在此处继续。

诚然,基于标准C++错误代码的处理似乎有点过度设计。我可能认为,理解它的关键是,如果你愿意的话,要从你的代码或库的用户的角度出发。

从文档中:

作用域枚举std::errc定义对应于 POSIX 错误代码的可移植错误条件的值。

std::errc常量用于在检查是否发生了某些特定错误情况时进行比较(如该页面上的示例所示)。

成功不是错误条件。

而是返回一个std::error_code,它可能包装这些错误条件之一,或者默认情况下没有错误条件(即成功)。

最新更新