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



当我开始利用C++17结构化绑定和if运算符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
    }
}

然后,当然,我认为为这样的返回类型提供一个可重复使用的模板会很好,这样就不会有人重复这对返回类型的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正是您想要了解的内容。甚至在描述中:

optional的常见用例是可能失败的函数的返回值。与其他方法(如std::pair<T,bool>(不同,由于意图是明确表达的,因此可选处理构建对象的成本很高,可读性更强。

示例中的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. 性能:为什么std::的构造是可选的<int>比std::对<int,bool>?尽管对于给定的例子来说,最新的与-O3的叮当声看起来很有帮助

    注意:为了简洁起见,为process添加了static,以防止生成用于外部链接的版本

  2. 若对象是默认构造的,它将返回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()必须返回int

最新更新