首页 > 解决方案 > 用于返回带有布尔结果标志的值的标准模板

问题描述

当我开始利用 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++17c++-standard-library

解决方案


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

optional 的一个常见用例是可能失败的函数的返回值。与其他方法相反,如std::pair<T,bool>, optional 可以很好地处理构建成本高的对象并且更具可读性,因为意图是明确表达的。

示例中的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<int> 的构造比 std::pair<int, bool> 更昂贵?尽管对于给定的示例,带有 -O3 的最新 clang 看起来非常有说服力

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

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

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


推荐阅读