将可选值初始化为 null 或值的体面习惯用法?

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

动机

随着 C++ 获得了可选值(在 C++17 中),现在通常需要编写以下内容:

如果条件成立,则用某个表达式初始化我的变量;如果条件不成立,请将我的变量保留为空/未分配

我们如何用 C++ 编写它?假设我们的表达式是

int
类型。人们希望可行的“理想”或最方便的语法是:

auto myopt = some_condition ? std::nullopt : 123;

但可选的是库类型,该语言对此一无所知,因此没有太多理由将

nullopt_t
int
协调为
optional<int>

所以,让我们尝试更详细一点:

std::optional<int> myopt = some_condition ? std::nullopt : 123;

这仍然失败,因为

int
无法转换为
nullopt_t
,反之亦然。

我们可以这样写:

auto myopt = some_condition ? std::nullopt : std::optional<int>(123);

这还可以。但如果我们的类型不是普通整数而是更复杂的东西,我们又会遇到麻烦:

struct mystruct { int x; double y; };

/// -snip-

auto myopt = some_condition ? std::nullopt : std::optional<mystruct>{ 12, 3.4 };

...无法编译。

所以,

实际问题

使用值或 nullopt 初始化可选值的体面、简洁(DRY...)习惯用法是什么?请注意,它也必须适用于更复杂的类型。

c++ c++17 option-type idioms
1个回答
2
投票

这里有三种选择,从我最不喜欢的到我最喜欢的:

  1. 使用
    in_place_t
  2. 使用CTAD
  3. 使用实用函数

替代方案 1:使用
std::optional

的显式安置构造

在您的问题中,您尝试使用

optional<T>
nullopt_t
pr-value
来初始化 T。但是 - 在可选选项中就地构建
T
怎么样?事实上,通过明确地说你想这样做,这是可能的,尽管不是很漂亮。
optional<T>
构造函数:

template< class... Args >
constexpr explicit optional( std::in_place_t, Args&&... args );

在你的情况下,它的使用意味着写作:

auto myopt = some_condition ? std::nullopt : std::optional<mystruct>{ std::in_place_t{}, 12, 3.4 };

编译并执行您想要的操作。可以观察到干燥,但它并不漂亮。

替代方案 2:使用演绎指南

让我们尝试对代码进行最小更改的方法。

幸运的是,在 C++17 中我们不仅仅获得了可选的,我们还获得了类模板参数推导(CTAD)指南,特别是针对可选的。所以,这有效:

auto myopt = some_condition ? std::nullopt : std::optional{ mystruct{ 12, 3.4 } };

并且您刚刚替换了

optional<T>{ ... }
{
with
可选{ T{ ... } }`。还不错。

替代方案 3:为其编写一个函数

如果你希望初始化更简洁(同时仍然具有合理的可读性),你可以写:

template <typename T>
auto value_if(T&& t, bool cond) {
    return cond ? std::nullopt : std::optional{ std::forward<T>(t) };
}

然后像这样使用它:

auto myopt = value_if(mystruct{12, 3.4}, some_condition);

这是我目前最喜欢的方法:-)

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