返回带有布尔结果标志的值的标准模板

standard template for returning a value with a boolean result flag

当我开始利用 C++17 结构化绑定和 if operator init 语句来进行更优雅的函数结果报告和检查时,如果符合 C++ 核心指南 F21,我开始执行以下操作:

std::pair<bool, int>Foo()
{
    return {true, 42}; //true means that function complete with no error and that 42 is a good value
}

void main(void)
{
    if (auto [Result, Value] = Foo(); Result)
    {
        //Do something with the return value here
    }
}

然后,当然,我认为如果有一个可重复使用的模板用于此类 return 类型,这样就没有人必须复制该对的 bool 部分:

template <typename T> using validated = std::pair<bool,T>;

validated<int> Foo()
{
    return {true, 42};
}

void main(void)
{
    if (auto [Result, Value] = Foo(); Result)
    {
        //Do something with the return value here
    }
}

这对我来说非常有用,但现在我想知道是否有某种与此模板等效的标准,这样我就不必重新发明轮子并自己定义它。似乎任意类型值加上有效性标志将是一个有用的结构,但我在标准库中找不到任何东西。我错过了什么吗?

std::optional 正是您要问的。它甚至在描述中:

A common use case for optional is the return value of a function that may fail. As opposed to other approaches, such as std::pair<T,bool>, optional handles expensive-to-construct objects well and is more readable, as the intent is expressed explicitly.

示例中的 if 看起来更直接一些:

#include <optional>
#include <iostream>

std::optional<int> Foo(bool fail)
{
    if (!fail) return {42};
    return {};
}

void process(bool fail) {
    if (auto val = Foo(fail)) {
        std::cout << val.value() << '\n';
    } else {
        std::cout << "No value!\n";
    }    
}

int main() {
    std::optional<int> oi;
    process(true);
    process(false);
}

如果你真的想明确地使用 Value 那么你总是可以通过成功分支上的引用来解压它,即 auto Value = val.value();

您需要注意一些注意事项。 2 从我的头顶开始:

  1. 性能: although for the given example up-to-date clang with -O3 looks pretty convicing

    Note: static was added for process for brevity - to prevent generation of version for external linking.

  2. 如果对象是默认构造的,它将return false。这可能会让一些人感到惊讶,optional 的默认构造不会默认构造基础值。

编辑: 在发表评论后,我决定明确声明 没有任何类似于 pair<T,bool> 的类型别名或与标准库兼容的类似内容。证明某些东西不存在并不容易,但如果存在这样的类型,标准库肯定会在 insert 的声明中使用它,但事实并非如此;因此,我强烈暗示它周围没有任何语义包装器。

您可能对提议的 std::expected 感兴趣。

它的界面非常接近std::optional。的主要优点 expected<T, E> 优于 optional<T> 的是传输错误的能力:

enum class errc {err1, err2, err3};

std::expected<int, errc> Foo()
{
  if (/* error condition 1 */)  return std::unexpected(errc::err1);

  // ... checking other error conditions

  return 42;  // no error condition (42 is a good value)
              // implicit conversion from `int` to `expected<int, errc>`
              // avoid boilerplate code
}

int main()
{
  auto q = Foo();

  if (q)
  {
    // Do something with the return value here
  }
}

您还可以看看:


作为旁注 main() must return int