当我开始利用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个:
- 性能:为什么std::的构造是可选的<int>比std::对<int,bool>?尽管对于给定的例子来说,最新的与-O3的叮当声看起来很有帮助
注意:为了简洁起见,为
process
添加了static
,以防止生成用于外部链接的版本 - 若对象是默认构造的,它将返回
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
。