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

问题描述 投票:0回答:2

当我开始利用 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
    }
}

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

c++ c++17 c++-standard-library
2个回答
10
投票

std::可选正是您要问的。甚至在描述中:

可选的一个常见用例是可能失败的函数的返回值。与其他方法(例如

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::Optional 的构造比 std::pair 更昂贵尽管对于给定的示例带有 -O3 的最新 clang 看起来相当令人信服

    注意:为简洁起见,为

    static
    添加了
    process
    - 以防止生成外部链接版本。

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

编辑: 在评论之后,我决定明确声明 不存在类似

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


3
投票

您可能对 提议的

std::expected
(在 C++23 中引入)感兴趣。

它的界面与

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

© www.soinside.com 2019 - 2024. All rights reserved.