由于我开始利用C ++ 17结构化绑定,并且如果运算符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
}
}
这对我来说很棒,但是现在我想知道是否有某种等同于此模板的标准,这样我就不必重新发明轮子并自己定义它了。似乎一个带有有效性标志的任意类型值将是一个有用的构造,但是我在标准库中找不到任何内容。我想念什么吗?
答案 0 :(得分:9)
std::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从我的头顶开始:
注意:为简洁起见,为
static
添加了process
-为防止生成用于外部链接的版本。
false
。可能会感到有些惊讶,optional
的默认构造不是默认构造基础价值。编辑:
在评论之后,我决定明确声明没有类似于pair<T,bool>
的类型别名或与标准库兼容的类似名称。要证明不存在某些东西并不容易,但是如果存在这样的类型,标准库肯定会在insert
的声明中使用它,但事实并非如此。因此,我强烈暗示它周围没有任何语义包装器。
答案 1 :(得分:1)
您可能对拟议的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
}
}
您也可以看看: