28

我喜欢在我的 C++ 代码中使用 std::experimental::optional,但问题是 value_or 要求默认值与可选值的类型相同。

当我想要一个包含 int 或包含错误消息的可选项时,这不能很好地工作。

Result<T, E>我想我可以使用一个带有布尔值的联合结构来指示该值是否存在或者它是一个错误,但如果 C++ 只是具有像 Rust 这样的类型肯定会很好。

有没有这样的类型?为什么Boost没有实现它?

Result 确实比 Option 有用得多,而且 Boost 的人肯定知道它的存在。也许我会去阅读 Rust 实现,然后将其复制到 C++?

前任:

// Function either returns a file descriptor for a listening socket or fails
// and returns a nullopt value.
// My issue: error messages are distributed via perror.
std::experimental::optional<int> get_tcp_listener(const char *ip_and_port);
// You can use value_or to handle error, but the error message isn't included!
// I have to write my own error logger that is contained within
// get_tcp_listener. I would really appreciate if it returned the error
// message on failure, rather than an error value.
int fd = get_tcp_listener("127.0.0.1:9123").value_or(-1);
// Rust has a type which does what I'm talking about:
let fd = match get_tcp_listener("127.0.0.1:9123") {
    Ok(fd) => fd,
    Err(msg) => { log_error(msg); return; },
}
4

4 回答 4

36

optional<T>T和虚无 ( nullopt_t) 的非对称类型安全联合。您可以查询它是否有Twith explicit operator bool,并T用 unary 取出*。不对称意味着可选的“更喜欢”是 a T,这就是为什么不合格的操作(like *or operator bool)指的是它的T本质。

variant<A,B,C>来自论文 n4218A,BC(etc) 的对称类型安全联合。 boost::variant总是参与,而且std::experimental::variant几乎总是参与。

*由于它是对称的,所以一元返回没有唯一类型,explicit operator bool也不能说太多有趣的东西,所以都不支持。

相反,您必须访问它,或查询它的特定类型。

std::experimental::expected<E, T>来自论文 n4015是一个不对称的类型安全联合。它要么是T要么E。但是optional,它“更喜欢”成为T; 它有一个explicit operator bool告诉你它是否是一个T,并且一元*得到T.

从某种意义上说,expected<E,T>是一个optional<T>,但是当为空而不是浪费它存储的空间时E,您可以查询它。

Result<T,E>似乎接近expected<E,T>(请注意,从 n4015 开始,参数的顺序与 相比交换Result)。

于 2015-08-20T20:22:42.707 回答
10

您正在寻找的正是 Alexandrescu 的预期。我建议听听他的演讲以深入了解:https ://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012-Andrei-Alexandrescu-Systematic-Error-Handling-in-C 。他实际上是逐行执行实现,您可以轻松地自己编写并在此之后很好地使用它。

Variant 是一个更通用的工具,它可以被强制做你想做的事情,但你最好按照预期进行。

于 2015-08-20T19:45:32.847 回答
7

如果不仅涉及 boost ,您可以使用result。这是一个不错的单头容器。

于 2017-11-21T09:43:35.467 回答
4

optional按照设计,要么包含某种类型的值,要么什么都不包含。

您可能正在寻找类似Boost::Variant.

这还不是标准库的一部分,尽管最终可能会是这样。

于 2015-08-20T19:27:58.213 回答